UNPKG

myinvois-sdk

Version:

TypeScript SDK for interacting with the Malaysia e-invoicing system (MyInvois) API

193 lines (192 loc) 7.78 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.InvoiceService = void 0; const document_signer_1 = require("../utils/document-signer"); const invoice_1 = require("../models/invoice"); const crypto = __importStar(require("crypto")); /** * Service for invoice operations */ class InvoiceService { /** * Creates a new invoice service * @param httpClient The HTTP client to use * @param authService The authentication service to use * @param certificateHandler The certificate handler to use * @param config The MyInvois configuration */ constructor(httpClient, authService, certificateHandler, config) { this.httpClient = httpClient; this.authService = authService; this.certificateHandler = certificateHandler; this.documentSigner = new document_signer_1.DocumentSigner(certificateHandler); this.config = config; } /** * Sign an invoice * @param invoice The invoice to sign * @returns A promise resolving to the signed invoice */ async signInvoice(invoice) { return this.documentSigner.signInvoice(invoice); } /** * Submit a signed invoice * @param signedInvoice The signed invoice to submit * @param authTIN The TIN to use for authentication * @returns A promise resolving to the submission result */ async submitInvoice(signedInvoice, authTIN) { console.log('signedInvoice', JSON.stringify(signedInvoice, null, 2)); let documentB64 = Buffer.from(JSON.stringify(signedInvoice)).toString('base64'); let documentToSubmit = { format: 'JSON', document: documentB64, documentHash: this.calculateSHA256Hex(JSON.stringify(signedInvoice)), codeNumber: signedInvoice.invoice.id, //signature: signature }; const token = await this.authService.getToken(authTIN); const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }; const url = `${this.config.transactionUrl}/api/v1.0/documentsubmissions/`; const payload = { documents: [documentToSubmit] }; console.log('payload', JSON.stringify(payload, null, 2)); // get the payload size in KB :: //console.log('payload', JSON.stringify(signedDocuments[0])); console.log('payload size', JSON.stringify(payload).length / 1024); try { console.log('Submitting invoice to MyInvois:', payload); const response = await this.httpClient.post(url, payload, { headers }); return response; } catch (error) { console.error('Failed to submit invoice to MyInvois:', error); console.log('error', JSON.stringify(error, null, 2)); throw new Error('Invoice submission failed'); } } /** * Submit multiple signed invoices * @param signedInvoices The signed invoices to submit * @param authTIN The TIN to use for authentication * @returns A promise resolving to the submission result */ async submitInvoices(signedInvoices, authTIN) { const token = await this.authService.getToken(authTIN); const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }; const url = `${this.config.transactionUrl}/api/v1.0/documentsubmissions/`; const payload = { documents: signedInvoices.map(invoice => invoice.toJSON()) }; try { const response = await this.httpClient.post(url, payload, { headers }); return response; } catch (error) { console.error('Failed to submit invoices to MyInvois:', error); throw new Error('Invoice submission failed'); } } /** * Create a builder for an invoice * @returns An invoice instance for building */ createInvoice() { return new invoice_1.Invoice(); } calculateSHA256Hex(input) { try { // Create a hash object for SHA-256 const hash = crypto.createHash('sha256'); // Update the hash object with the input string hash.update(input, 'utf8'); // Calculate the digest and return it as a hexadecimal string return hash.digest('hex'); } catch (error) { throw new Error(`Failed to calculate SHA256 hash: ${error}`); } } /** * Cancel an invoice * @param documentUuid The UUID of the document to cancel * @param reason The reason for cancellation * @param authTIN The TIN to use for authentication * @returns A promise resolving to the cancellation result */ async cancelInvoice(documentUuid, reason, authTIN) { const token = await this.authService.getToken(authTIN); const headers = { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }; const url = `${this.config.transactionUrl}/api/v1.0/documents/state/${documentUuid}/state`; const payload = { status: 'cancelled', reason: reason.substring(0, 300) // Limit to 300 chars as per docs }; try { const response = await this.httpClient.put(url, payload, { headers }); return response; } catch (error) { if (error.statusCode === 400) { const errorCode = error.responseData?.error?.code; switch (errorCode) { case 'OperationPeriodOver': throw new Error('Cancellation period has expired (72 hours)'); case 'IncorrectState': throw new Error('Invoice cannot be cancelled in its current state'); case 'ActiveReferencingDocuments': throw new Error('Invoice has active referencing documents'); default: throw new Error(error.responseData?.error?.message || 'Error cancelling invoice'); } } console.error('Failed to cancel invoice:', error); throw new Error('Invoice cancellation failed'); } } } exports.InvoiceService = InvoiceService;