@timbra-ec/whatsapp 0.1.0-dev.20260403050717
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/dist/client.d.ts +10 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +35 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/send-invoice-whatsapp.d.ts +13 -0
- package/dist/send-invoice-whatsapp.d.ts.map +1 -0
- package/dist/send-invoice-whatsapp.js +55 -0
- package/dist/send-invoice-whatsapp.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +32 -0
- package/src/client.ts +61 -0
- package/src/index.ts +2 -0
- package/src/send-invoice-whatsapp.ts +60 -0
- package/src/types.ts +27 -0
- package/tsconfig.json +8 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WhatsAppConfig } from './types';
|
|
2
|
+
export declare function sendWhatsAppMessage(config: WhatsAppConfig, payload: Record<string, unknown>): Promise<{
|
|
3
|
+
messageId: string;
|
|
4
|
+
}>;
|
|
5
|
+
export declare class WhatsAppApiError extends Error {
|
|
6
|
+
readonly code: string;
|
|
7
|
+
readonly statusCode: number;
|
|
8
|
+
constructor(message: string, code: string, statusCode: number);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAgB7C,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA8BhC;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,IAAI,EAAE,MAAM;aACZ,UAAU,EAAE,MAAM;gBAFlC,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM;CAKrC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const GRAPH_API_VERSION = 'v21.0';
|
|
2
|
+
const BASE_URL = `https://graph.facebook.com/${GRAPH_API_VERSION}`;
|
|
3
|
+
export async function sendWhatsAppMessage(config, payload) {
|
|
4
|
+
const url = `${BASE_URL}/${config.phoneNumberId}/messages`;
|
|
5
|
+
const response = await fetch(url, {
|
|
6
|
+
method: 'POST',
|
|
7
|
+
headers: {
|
|
8
|
+
Authorization: `Bearer ${config.token}`,
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
},
|
|
11
|
+
body: JSON.stringify(payload),
|
|
12
|
+
});
|
|
13
|
+
const data = (await response.json());
|
|
14
|
+
if (!response.ok || data.error) {
|
|
15
|
+
const error = data.error;
|
|
16
|
+
const code = error?.code === 4 || error?.error_subcode === 33 ? 'RATE_LIMITED' : 'API_ERROR';
|
|
17
|
+
throw new WhatsAppApiError(error?.message ?? `WhatsApp API returned ${response.status}`, code, response.status);
|
|
18
|
+
}
|
|
19
|
+
const messageId = data.messages?.[0]?.id;
|
|
20
|
+
if (!messageId) {
|
|
21
|
+
throw new WhatsAppApiError('No message ID in response', 'UNEXPECTED_RESPONSE', response.status);
|
|
22
|
+
}
|
|
23
|
+
return { messageId };
|
|
24
|
+
}
|
|
25
|
+
export class WhatsAppApiError extends Error {
|
|
26
|
+
code;
|
|
27
|
+
statusCode;
|
|
28
|
+
constructor(message, code, statusCode) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this.statusCode = statusCode;
|
|
32
|
+
this.name = 'WhatsAppApiError';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAEA,MAAM,iBAAiB,GAAG,OAAO,CAAA;AACjC,MAAM,QAAQ,GAAG,8BAA8B,iBAAiB,EAAE,CAAA;AAalE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,OAAgC;IAEhC,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,MAAM,CAAC,aAAa,WAAW,CAAA;IAE1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,MAAM,CAAC,KAAK,EAAE;YACvC,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;KAC9B,CAAC,CAAA;IAEF,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAqB,CAAA;IAExD,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACxB,MAAM,IAAI,GAAG,KAAK,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,EAAE,aAAa,KAAK,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,WAAW,CAAA;QAC5F,MAAM,IAAI,gBAAgB,CACxB,KAAK,EAAE,OAAO,IAAI,yBAAyB,QAAQ,CAAC,MAAM,EAAE,EAC5D,IAAI,EACJ,QAAQ,CAAC,MAAM,CAChB,CAAA;IACH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;IACxC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,gBAAgB,CAAC,2BAA2B,EAAE,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IACjG,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,CAAA;AACtB,CAAC;AAED,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAGvB;IACA;IAHlB,YACE,OAAe,EACC,IAAY,EACZ,UAAkB;QAElC,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAQ;QAGlC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAA;IAChC,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AACpF,YAAY,EAAE,cAAc,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DeliveryResult, SendInvoiceWhatsAppParams, WhatsAppConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Pre-approved template name that must be registered in Meta Business Manager.
|
|
4
|
+
*
|
|
5
|
+
* Expected template structure:
|
|
6
|
+
* Header: Document (PDF attachment)
|
|
7
|
+
* Body: "Estimado cliente, su factura {{1}} de {{2}} ha sido autorizada por el SRI.
|
|
8
|
+
* Adjuntamos el comprobante electronico (RIDE) para su registro."
|
|
9
|
+
* Language: es
|
|
10
|
+
*/
|
|
11
|
+
export declare const INVOICE_TEMPLATE_NAME = "invoice_notification";
|
|
12
|
+
export declare function sendInvoiceWhatsApp(config: WhatsAppConfig, params: SendInvoiceWhatsAppParams): Promise<DeliveryResult>;
|
|
13
|
+
//# sourceMappingURL=send-invoice-whatsapp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-invoice-whatsapp.d.ts","sourceRoot":"","sources":["../src/send-invoice-whatsapp.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAExF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,yBAAyB,CAAA;AAE3D,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,cAAc,CAAC,CA0CzB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { sendWhatsAppMessage, WhatsAppApiError } from './client';
|
|
2
|
+
/**
|
|
3
|
+
* Pre-approved template name that must be registered in Meta Business Manager.
|
|
4
|
+
*
|
|
5
|
+
* Expected template structure:
|
|
6
|
+
* Header: Document (PDF attachment)
|
|
7
|
+
* Body: "Estimado cliente, su factura {{1}} de {{2}} ha sido autorizada por el SRI.
|
|
8
|
+
* Adjuntamos el comprobante electronico (RIDE) para su registro."
|
|
9
|
+
* Language: es
|
|
10
|
+
*/
|
|
11
|
+
export const INVOICE_TEMPLATE_NAME = 'invoice_notification';
|
|
12
|
+
export async function sendInvoiceWhatsApp(config, params) {
|
|
13
|
+
const payload = {
|
|
14
|
+
messaging_product: 'whatsapp',
|
|
15
|
+
to: params.phoneNumber,
|
|
16
|
+
type: 'template',
|
|
17
|
+
template: {
|
|
18
|
+
name: INVOICE_TEMPLATE_NAME,
|
|
19
|
+
language: { code: 'es' },
|
|
20
|
+
components: [
|
|
21
|
+
{
|
|
22
|
+
type: 'header',
|
|
23
|
+
parameters: [
|
|
24
|
+
{
|
|
25
|
+
type: 'document',
|
|
26
|
+
document: {
|
|
27
|
+
link: params.ridePdfUrl,
|
|
28
|
+
filename: `Factura_${params.invoiceNumber}.pdf`,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
type: 'body',
|
|
35
|
+
parameters: [
|
|
36
|
+
{ type: 'text', text: params.invoiceNumber },
|
|
37
|
+
{ type: 'text', text: params.businessName },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
const result = await sendWhatsAppMessage(config, payload);
|
|
45
|
+
return { success: true, messageId: result.messageId };
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error instanceof WhatsAppApiError) {
|
|
49
|
+
return { success: false, error: error.message, code: error.code };
|
|
50
|
+
}
|
|
51
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
52
|
+
return { success: false, error: message, code: 'UNKNOWN' };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=send-invoice-whatsapp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-invoice-whatsapp.js","sourceRoot":"","sources":["../src/send-invoice-whatsapp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAGhE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,CAAA;AAE3D,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,MAAiC;IAEjC,MAAM,OAAO,GAAG;QACd,iBAAiB,EAAE,UAAU;QAC7B,EAAE,EAAE,MAAM,CAAC,WAAW;QACtB,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,qBAAqB;YAC3B,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;YACxB,UAAU,EAAE;gBACV;oBACE,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV;4BACE,IAAI,EAAE,UAAU;4BAChB,QAAQ,EAAE;gCACR,IAAI,EAAE,MAAM,CAAC,UAAU;gCACvB,QAAQ,EAAE,WAAW,MAAM,CAAC,aAAa,MAAM;6BAChD;yBACF;qBACF;iBACF;gBACD;oBACE,IAAI,EAAE,MAAM;oBACZ,UAAU,EAAE;wBACV,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,aAAa,EAAE;wBAC5C,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,YAAY,EAAE;qBAC5C;iBACF;aACF;SACF;KACF,CAAA;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACzD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAA;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,gBAAgB,EAAE,CAAC;YACtC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QACnE,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAA;QACxE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAA;IAC5D,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** WhatsApp Cloud API configuration */
|
|
2
|
+
export interface WhatsAppConfig {
|
|
3
|
+
token: string;
|
|
4
|
+
phoneNumberId: string;
|
|
5
|
+
}
|
|
6
|
+
/** Parameters for sending an invoice via WhatsApp */
|
|
7
|
+
export interface SendInvoiceWhatsAppParams {
|
|
8
|
+
phoneNumber: string;
|
|
9
|
+
invoiceNumber: string;
|
|
10
|
+
ridePdfUrl: string;
|
|
11
|
+
businessName: string;
|
|
12
|
+
}
|
|
13
|
+
interface DeliverySuccess {
|
|
14
|
+
success: true;
|
|
15
|
+
messageId: string;
|
|
16
|
+
}
|
|
17
|
+
interface DeliveryFailure {
|
|
18
|
+
success: false;
|
|
19
|
+
error: string;
|
|
20
|
+
code?: string;
|
|
21
|
+
}
|
|
22
|
+
/** Result of a WhatsApp delivery attempt */
|
|
23
|
+
export type DeliveryResult = DeliverySuccess | DeliveryFailure;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,qDAAqD;AACrD,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,IAAI,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,KAAK,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,eAAe,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@timbra-ec/whatsapp",
|
|
3
|
+
"version": "0.1.0-dev.20260403050717",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/timbra-ec/timbra-app.git",
|
|
10
|
+
"directory": "packages/whatsapp"
|
|
11
|
+
},
|
|
12
|
+
"type": "module",
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@timbra-ec/types": "0.1.0-dev.20260403050717"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"typescript": "^5.8.2"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"lint": "echo 'no lint configured yet'"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { WhatsAppConfig } from './types'
|
|
2
|
+
|
|
3
|
+
const GRAPH_API_VERSION = 'v21.0'
|
|
4
|
+
const BASE_URL = `https://graph.facebook.com/${GRAPH_API_VERSION}`
|
|
5
|
+
|
|
6
|
+
interface GraphApiResponse {
|
|
7
|
+
messages?: { id: string }[]
|
|
8
|
+
error?: {
|
|
9
|
+
message: string
|
|
10
|
+
type: string
|
|
11
|
+
code: number
|
|
12
|
+
error_subcode?: number
|
|
13
|
+
fbtrace_id?: string
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function sendWhatsAppMessage(
|
|
18
|
+
config: WhatsAppConfig,
|
|
19
|
+
payload: Record<string, unknown>,
|
|
20
|
+
): Promise<{ messageId: string }> {
|
|
21
|
+
const url = `${BASE_URL}/${config.phoneNumberId}/messages`
|
|
22
|
+
|
|
23
|
+
const response = await fetch(url, {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${config.token}`,
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify(payload),
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const data = (await response.json()) as GraphApiResponse
|
|
33
|
+
|
|
34
|
+
if (!response.ok || data.error) {
|
|
35
|
+
const error = data.error
|
|
36
|
+
const code = error?.code === 4 || error?.error_subcode === 33 ? 'RATE_LIMITED' : 'API_ERROR'
|
|
37
|
+
throw new WhatsAppApiError(
|
|
38
|
+
error?.message ?? `WhatsApp API returned ${response.status}`,
|
|
39
|
+
code,
|
|
40
|
+
response.status,
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const messageId = data.messages?.[0]?.id
|
|
45
|
+
if (!messageId) {
|
|
46
|
+
throw new WhatsAppApiError('No message ID in response', 'UNEXPECTED_RESPONSE', response.status)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { messageId }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class WhatsAppApiError extends Error {
|
|
53
|
+
constructor(
|
|
54
|
+
message: string,
|
|
55
|
+
public readonly code: string,
|
|
56
|
+
public readonly statusCode: number,
|
|
57
|
+
) {
|
|
58
|
+
super(message)
|
|
59
|
+
this.name = 'WhatsAppApiError'
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { sendWhatsAppMessage, WhatsAppApiError } from './client'
|
|
2
|
+
import type { DeliveryResult, SendInvoiceWhatsAppParams, WhatsAppConfig } from './types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pre-approved template name that must be registered in Meta Business Manager.
|
|
6
|
+
*
|
|
7
|
+
* Expected template structure:
|
|
8
|
+
* Header: Document (PDF attachment)
|
|
9
|
+
* Body: "Estimado cliente, su factura {{1}} de {{2}} ha sido autorizada por el SRI.
|
|
10
|
+
* Adjuntamos el comprobante electronico (RIDE) para su registro."
|
|
11
|
+
* Language: es
|
|
12
|
+
*/
|
|
13
|
+
export const INVOICE_TEMPLATE_NAME = 'invoice_notification'
|
|
14
|
+
|
|
15
|
+
export async function sendInvoiceWhatsApp(
|
|
16
|
+
config: WhatsAppConfig,
|
|
17
|
+
params: SendInvoiceWhatsAppParams,
|
|
18
|
+
): Promise<DeliveryResult> {
|
|
19
|
+
const payload = {
|
|
20
|
+
messaging_product: 'whatsapp',
|
|
21
|
+
to: params.phoneNumber,
|
|
22
|
+
type: 'template',
|
|
23
|
+
template: {
|
|
24
|
+
name: INVOICE_TEMPLATE_NAME,
|
|
25
|
+
language: { code: 'es' },
|
|
26
|
+
components: [
|
|
27
|
+
{
|
|
28
|
+
type: 'header',
|
|
29
|
+
parameters: [
|
|
30
|
+
{
|
|
31
|
+
type: 'document',
|
|
32
|
+
document: {
|
|
33
|
+
link: params.ridePdfUrl,
|
|
34
|
+
filename: `Factura_${params.invoiceNumber}.pdf`,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
type: 'body',
|
|
41
|
+
parameters: [
|
|
42
|
+
{ type: 'text', text: params.invoiceNumber },
|
|
43
|
+
{ type: 'text', text: params.businessName },
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const result = await sendWhatsAppMessage(config, payload)
|
|
52
|
+
return { success: true, messageId: result.messageId }
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error instanceof WhatsAppApiError) {
|
|
55
|
+
return { success: false, error: error.message, code: error.code }
|
|
56
|
+
}
|
|
57
|
+
const message = error instanceof Error ? error.message : 'Unknown error'
|
|
58
|
+
return { success: false, error: message, code: 'UNKNOWN' }
|
|
59
|
+
}
|
|
60
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** WhatsApp Cloud API configuration */
|
|
2
|
+
export interface WhatsAppConfig {
|
|
3
|
+
token: string
|
|
4
|
+
phoneNumberId: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** Parameters for sending an invoice via WhatsApp */
|
|
8
|
+
export interface SendInvoiceWhatsAppParams {
|
|
9
|
+
phoneNumber: string // E.164 format, e.g., "+593991234567"
|
|
10
|
+
invoiceNumber: string // e.g., "001-001-000000042"
|
|
11
|
+
ridePdfUrl: string
|
|
12
|
+
businessName: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface DeliverySuccess {
|
|
16
|
+
success: true
|
|
17
|
+
messageId: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface DeliveryFailure {
|
|
21
|
+
success: false
|
|
22
|
+
error: string
|
|
23
|
+
code?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Result of a WhatsApp delivery attempt */
|
|
27
|
+
export type DeliveryResult = DeliverySuccess | DeliveryFailure
|