diff --git a/server/.env b/server/.env
index 2d6e7b7..a9a1163 100644
--- a/server/.env
+++ b/server/.env
@@ -69,6 +69,7 @@ FILE_SERVER_URL = http://localhost:4000/
FILE_SERVER_URL_prod = https://files.turnosxpress.com.ar/
SYS_ADMIN_API_PUBLIC_KEY = keys/tx-sysadmin-public.key
+ARCA_ENVIRONMENT=homologation
ARCA_WSAA_URL=https://wsaahomo.afip.gov.ar/ws/services/LoginCms
ARCA_WSFE_URL=https://wswhomo.afip.gov.ar/wsfev1/service.asmx
diff --git a/server/.env.prod b/server/.env.prod
index 0635964..85a305b 100644
--- a/server/.env.prod
+++ b/server/.env.prod
@@ -67,6 +67,7 @@ SYSTEM_KEY = ad7c956a-76bf-45hdr60-8a50-2ca7b2180997
FILE_SERVER_URL = https://files.turnosxpress.com.ar/
SYS_ADMIN_API_PUBLIC_KEY = keys/tx-sysadmin-public.key
+ARCA_ENVIRONMENT=production
ARCA_WSAA_URL=https://wsaa.afip.gov.ar/ws/services/LoginCms
ARCA_WSFE_URL=https://servicios1.afip.gov.ar/wsfev1/service.asmx
diff --git a/server/src/Models/ArcaCredentials/ArcaCredentials.Interface.ts b/server/src/Models/ArcaCredentials/ArcaCredentials.Interface.ts
index 98cc8da..7b3f6bb 100644
--- a/server/src/Models/ArcaCredentials/ArcaCredentials.Interface.ts
+++ b/server/src/Models/ArcaCredentials/ArcaCredentials.Interface.ts
@@ -1,4 +1,5 @@
import { IArcaCredentialDocument } from "./ArcaCredentials.Adapter.Mongoose";
+import { ARCA_WSAA_ENVIRONMENT, ARCA_WSAA_SERVICE } from "../ArcaWsaaTokens/ArcaWsaaTokens.Interface";
export enum ARCA_CREDENTIAL_STATUS {
CSR_GENERATED = "CSR_GENERATED",
@@ -26,8 +27,9 @@ export type TestArcaWsaaLoginParams = {
export type ArcaWsaaLoginTestResult = {
status: "cached" | "created";
- environment: "homologation";
- service: "wsfe";
+ environment: ARCA_WSAA_ENVIRONMENT;
+ service: ARCA_WSAA_SERVICE;
+ endpoints: ArcaEndpointMetadata;
expirationTime: Date;
cached: boolean;
};
@@ -38,8 +40,9 @@ export type ArcaWsfeLastVoucherParams = {
};
export type ArcaWsfeLastVoucherResult = {
- environment: "homologation";
- service: "wsfe";
+ environment: ARCA_WSAA_ENVIRONMENT;
+ service: ARCA_WSAA_SERVICE;
+ endpoints: ArcaEndpointMetadata;
pointOfSale: number;
voucherType: 11;
lastVoucherNumber: number;
@@ -58,8 +61,9 @@ export type ArcaWsfeIssueFacturaCParams = {
};
export type ArcaWsfeIssueFacturaCResult = {
- environment: "homologation";
- service: "wsfe";
+ environment: ARCA_WSAA_ENVIRONMENT;
+ service: ARCA_WSAA_SERVICE;
+ endpoints: ArcaEndpointMetadata;
pointOfSale: number;
voucherType: 11;
voucherNumber: number;
@@ -78,9 +82,15 @@ export type ArcaWsfeDiagnosticsParams = {
sessionUser: string;
};
+export type ArcaEndpointMetadata = {
+ wsaaHost?: string;
+ wsfeHost?: string;
+};
+
export type ArcaWsfeDiagnosticsResult = {
- environment: "homologation";
- service: "wsfe";
+ environment: ARCA_WSAA_ENVIRONMENT;
+ service: ARCA_WSAA_SERVICE;
+ endpoints: ArcaEndpointMetadata;
dummy: {
ok: boolean;
appServer?: string;
diff --git a/server/src/Models/ArcaCredentials/ArcaCredentials.ts b/server/src/Models/ArcaCredentials/ArcaCredentials.ts
index 058cb2e..738edbc 100644
--- a/server/src/Models/ArcaCredentials/ArcaCredentials.ts
+++ b/server/src/Models/ArcaCredentials/ArcaCredentials.ts
@@ -200,6 +200,35 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
return parsedValue;
}
+ private getArcaEnvironment(): ARCA_WSAA_ENVIRONMENT {
+ const environment = (process.env.ARCA_ENVIRONMENT || ARCA_WSAA_ENVIRONMENT.HOMOLOGATION).trim().toLowerCase();
+
+ if (!Object.values(ARCA_WSAA_ENVIRONMENT).includes(environment as ARCA_WSAA_ENVIRONMENT)) {
+ throw new Error("ARCA_ENVIRONMENT debe ser 'homologation' o 'production'");
+ }
+
+ return environment as ARCA_WSAA_ENVIRONMENT;
+ }
+
+ private getEndpointHost(value?: string): string | undefined {
+ if (!value) {
+ return undefined;
+ }
+
+ try {
+ return new URL(value).host;
+ } catch {
+ return undefined;
+ }
+ }
+
+ private getArcaEndpointMetadata() {
+ return {
+ wsaaHost: this.getEndpointHost(process.env.ARCA_WSAA_URL),
+ wsfeHost: this.getEndpointHost(process.env.ARCA_WSFE_URL),
+ };
+ }
+
private signTraCms(traXml: string, certificatePem: string, privateKeyPem: string): string {
const p7 = forge.pkcs7.createSignedData();
p7.content = forge.util.createBuffer(traXml, "utf8");
@@ -270,7 +299,7 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
cached: boolean;
}> {
const service = ARCA_WSAA_SERVICE.WSFE;
- const environment = ARCA_WSAA_ENVIRONMENT.HOMOLOGATION;
+ const environment = this.getArcaEnvironment();
const cachedToken = await ArcaWsaaTokens.getValidToken({ companyId, service, environment });
if (cachedToken) {
@@ -582,7 +611,8 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
private parseWsfeIssueFacturaCReturn(
xml: string,
pointOfSale: number,
- voucherNumber: number
+ voucherNumber: number,
+ environment: ARCA_WSAA_ENVIRONMENT
): ArcaWsfeIssueFacturaCResult {
const faultString = this.extractXmlValue(xml, "faultstring");
@@ -600,8 +630,9 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
}
return {
- environment: ARCA_WSAA_ENVIRONMENT.HOMOLOGATION,
+ environment,
service: ARCA_WSAA_SERVICE.WSFE,
+ endpoints: this.getArcaEndpointMetadata(),
pointOfSale,
voucherType: FACTURA_C_VOUCHER_TYPE,
voucherNumber,
@@ -807,13 +838,14 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
await this.validateCompanyAdmin(data.companyId, data.sessionUser);
const service = ARCA_WSAA_SERVICE.WSFE;
- const environment = ARCA_WSAA_ENVIRONMENT.HOMOLOGATION;
+ const environment = this.getArcaEnvironment();
const loginTicket = await this.getWsaaLoginTicket(data.companyId);
return {
status: loginTicket.cached ? "cached" : "created",
environment,
service,
+ endpoints: this.getArcaEndpointMetadata(),
expirationTime: loginTicket.expirationTime,
cached: loginTicket.cached,
};
@@ -823,6 +855,7 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
await this.validateCompanyAdmin(data.companyId, data.sessionUser);
const fiscalProfile = await this.requireActiveFiscalProfile(data.companyId, data.sessionUser);
const loginTicket = await this.getWsaaLoginTicket(data.companyId);
+ const environment = this.getArcaEnvironment();
const voucherType = FACTURA_C_VOUCHER_TYPE;
let responseXml: string;
@@ -842,8 +875,9 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
}
return {
- environment: ARCA_WSAA_ENVIRONMENT.HOMOLOGATION,
+ environment,
service: ARCA_WSAA_SERVICE.WSFE,
+ endpoints: this.getArcaEndpointMetadata(),
pointOfSale: fiscalProfile.pointOfSale,
voucherType,
lastVoucherNumber: this.parseWsfeLastVoucherReturn(responseXml),
@@ -859,6 +893,7 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
const fiscalProfile = await this.requireActiveFiscalProfile(data.companyId, data.sessionUser);
const loginTicket = await this.getWsaaLoginTicket(data.companyId);
+ const environment = this.getArcaEnvironment();
const voucherType = 11;
const receiverDocumentType = this.parseXmlInteger(
data.receiverDocumentType ?? FINAL_CONSUMER_DOCUMENT_TYPE,
@@ -908,7 +943,8 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
"FECAESolicitar"
),
fiscalProfile.pointOfSale,
- voucherNumber
+ voucherNumber,
+ environment
);
} catch (error) {
throw new ArcaWsfeIssueFacturaCError(
@@ -927,11 +963,13 @@ class ArcaCredentialsManager implements IArcaCredentialsManager {
await this.validateCompanyAdmin(data.companyId, data.sessionUser);
const fiscalProfile = await this.requireActiveFiscalProfile(data.companyId, data.sessionUser);
const loginTicket = await this.getWsaaLoginTicket(data.companyId);
+ const environment = this.getArcaEnvironment();
const voucherType = 11;
const diagnostics: ArcaWsfeDiagnosticsResult = {
- environment: ARCA_WSAA_ENVIRONMENT.HOMOLOGATION,
+ environment,
service: ARCA_WSAA_SERVICE.WSFE,
+ endpoints: this.getArcaEndpointMetadata(),
dummy: { ok: false },
voucherTypes: { ok: false },
pointsOfSale: {
diff --git a/server/src/Models/ArcaWsaaTokens/ArcaWsaaTokens.Interface.ts b/server/src/Models/ArcaWsaaTokens/ArcaWsaaTokens.Interface.ts
index f5feb6d..adf972d 100644
--- a/server/src/Models/ArcaWsaaTokens/ArcaWsaaTokens.Interface.ts
+++ b/server/src/Models/ArcaWsaaTokens/ArcaWsaaTokens.Interface.ts
@@ -6,6 +6,7 @@ export enum ARCA_WSAA_SERVICE {
export enum ARCA_WSAA_ENVIRONMENT {
HOMOLOGATION = "homologation",
+ PRODUCTION = "production",
}
export type ArcaWsaaTokenLookupParams = {
diff --git a/txclient/src/app/admin/(organization-profile)/org/profile/[id]/cash/Cash.Service.tsx b/txclient/src/app/admin/(organization-profile)/org/profile/[id]/cash/Cash.Service.tsx
index d058aaf..6037649 100644
--- a/txclient/src/app/admin/(organization-profile)/org/profile/[id]/cash/Cash.Service.tsx
+++ b/txclient/src/app/admin/(organization-profile)/org/profile/[id]/cash/Cash.Service.tsx
@@ -19,8 +19,12 @@ export type ArcaWsfeLastVoucherParams = {
};
export type ArcaWsfeLastVoucherResult = {
- environment: "homologation";
+ environment: "homologation" | "production";
service: "wsfe";
+ endpoints?: {
+ wsaaHost?: string;
+ wsfeHost?: string;
+ };
pointOfSale: number;
voucherType: 11;
lastVoucherNumber: number;
diff --git a/txclient/src/app/admin/assistant/components/StepEngine/flows/ArcaTestConnectionFlow.tsx b/txclient/src/app/admin/assistant/components/StepEngine/flows/ArcaTestConnectionFlow.tsx
index 76593f5..93c25ad 100644
--- a/txclient/src/app/admin/assistant/components/StepEngine/flows/ArcaTestConnectionFlow.tsx
+++ b/txclient/src/app/admin/assistant/components/StepEngine/flows/ArcaTestConnectionFlow.tsx
@@ -4,15 +4,22 @@ import QuestionCard from "../../QuestionCard/QuestionCard";
export type ArcaWsaaTestResult = {
status?: string;
- environment?: string;
+ environment?: "homologation" | "production";
service?: string;
+ endpoints?: ArcaEndpointMetadata;
expirationTime?: string;
cached?: boolean;
};
+type ArcaEndpointMetadata = {
+ wsaaHost?: string;
+ wsfeHost?: string;
+};
+
export type ArcaWsfeDiagnosticsResult = {
- environment?: string;
+ environment?: "homologation" | "production";
service?: string;
+ endpoints?: ArcaEndpointMetadata;
dummy?: {
ok: boolean;
appServer?: string;
@@ -84,6 +91,7 @@ export default function ArcaTestConnectionFlow({ currentStepIndex, loading, diag