@ripwords/myinvois-client 0.1.6 → 0.1.7
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/package.json +5 -8
- package/.prettierrc +0 -8
- package/CHANGELOG.md +0 -152
- package/bun.lock +0 -460
- package/myinvois-cert.conf.template +0 -23
- package/scripts/gen-cert.sh +0 -159
- package/src/api/platform/platformLogin.ts +0 -34
- package/src/index.ts +0 -530
- package/src/types/classification-codes.d.ts +0 -115
- package/src/types/country-code.d.ts +0 -790
- package/src/types/currencies.d.ts +0 -383
- package/src/types/documents.d.ts +0 -869
- package/src/types/e-invoice.d.ts +0 -41
- package/src/types/index.d.ts +0 -24
- package/src/types/msic/0X.d.ts +0 -408
- package/src/types/msic/1X.d.ts +0 -210
- package/src/types/msic/2X.d.ts +0 -266
- package/src/types/msic/3X.d.ts +0 -114
- package/src/types/msic/4X.d.ts +0 -520
- package/src/types/msic/5X.d.ts +0 -144
- package/src/types/msic/6X.d.ts +0 -200
- package/src/types/msic/7X.d.ts +0 -132
- package/src/types/msic/8X.d.ts +0 -210
- package/src/types/msic/9X.d.ts +0 -186
- package/src/types/msic-codes.d.ts +0 -31
- package/src/types/payment-modes.d.ts +0 -41
- package/src/types/signatures.d.ts +0 -169
- package/src/types/state-codes.d.ts +0 -59
- package/src/types/tax-types.d.ts +0 -39
- package/src/types/unit/1X.d.ts +0 -16
- package/src/types/unit/2X.d.ts +0 -62
- package/src/types/unit/3X.d.ts +0 -17
- package/src/types/unit/4X.d.ts +0 -44
- package/src/types/unit/5X.d.ts +0 -26
- package/src/types/unit/6X.d.ts +0 -12
- package/src/types/unit/7X.d.ts +0 -12
- package/src/types/unit/8X.d.ts +0 -15
- package/src/types/unit/9X.d.ts +0 -11
- package/src/types/unit/AX.d.ts +0 -202
- package/src/types/unit/BX.d.ts +0 -212
- package/src/types/unit/CX.d.ts +0 -238
- package/src/types/unit/DX.d.ts +0 -212
- package/src/types/unit/EX.d.ts +0 -196
- package/src/types/unit/FX.d.ts +0 -236
- package/src/types/unit/GX.d.ts +0 -254
- package/src/types/unit/HX.d.ts +0 -234
- package/src/types/unit/IX.d.ts +0 -28
- package/src/types/unit/JX.d.ts +0 -190
- package/src/types/unit/KX.d.ts +0 -284
- package/src/types/unit/LX.d.ts +0 -228
- package/src/types/unit/MX.d.ts +0 -288
- package/src/types/unit/NX.d.ts +0 -226
- package/src/types/unit/OX.d.ts +0 -34
- package/src/types/unit/PX.d.ts +0 -224
- package/src/types/unit/QX.d.ts +0 -94
- package/src/types/unit/RX.d.ts +0 -28
- package/src/types/unit/SX.d.ts +0 -56
- package/src/types/unit/TX.d.ts +0 -44
- package/src/types/unit/UX.d.ts +0 -14
- package/src/types/unit/VX.d.ts +0 -13
- package/src/types/unit/WX.d.ts +0 -34
- package/src/types/unit/XX.d.ts +0 -825
- package/src/types/unit/YX.d.ts +0 -17
- package/src/types/unit/ZX.d.ts +0 -19
- package/src/types/unit-types.d.ts +0 -86
- package/src/utils/base64.ts +0 -7
- package/src/utils/certificate.ts +0 -60
- package/src/utils/document.ts +0 -852
- package/src/utils/getBaseUrl.ts +0 -5
- package/src/utils/helpers.ts +0 -552
- package/src/utils/signature-diagnostics.ts +0 -583
- package/src/utils/validation.ts +0 -268
- package/test/MyInvoiClientWithRealData.test.ts +0 -40
- package/test/MyInvoisClient.test.ts +0 -204
- package/test/base64.test.ts +0 -43
- package/test/dynamicInvoiceFeatures.test.ts +0 -451
- package/test/signAndSubmitInvoice.test.ts +0 -452
- package/test/signature-diagnostics.test.ts +0 -130
- package/tsconfig.json +0 -39
- package/tsdown.config.ts +0 -31
- package/vitest.config.ts +0 -8
|
@@ -1,451 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import type { InvoiceV1_1 } from '../src/types'
|
|
3
|
-
import {
|
|
4
|
-
PaymentHelpers,
|
|
5
|
-
CurrencyHelpers,
|
|
6
|
-
TaxHelpers,
|
|
7
|
-
AllowanceChargeHelpers,
|
|
8
|
-
DeliveryHelpers,
|
|
9
|
-
DocumentReferenceHelpers,
|
|
10
|
-
IndustryHelpers,
|
|
11
|
-
DateTimeHelpers,
|
|
12
|
-
InvoiceBuilder,
|
|
13
|
-
} from '../src/utils/helpers'
|
|
14
|
-
import { validateInvoice } from '../src/utils/validation'
|
|
15
|
-
import { generateCleanUBLDocument } from '../src/utils/document'
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* ⚠️ SECURITY NOTICE: This file uses environment variables for sensitive data.
|
|
19
|
-
* Never hardcode actual TIN, NRIC, certificates, or API credentials in test files.
|
|
20
|
-
* Use .env file for your actual values (already gitignored).
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
describe('Dynamic Invoice Features', () => {
|
|
24
|
-
describe('Helper Functions', () => {
|
|
25
|
-
it('should create different payment methods', () => {
|
|
26
|
-
const cash = PaymentHelpers.cash()
|
|
27
|
-
expect(cash.paymentMeansCode).toBe('01')
|
|
28
|
-
expect(cash.paymentTerms).toBe('Cash payment')
|
|
29
|
-
|
|
30
|
-
const bankTransfer = PaymentHelpers.bankTransfer('ACC123', '2025-02-01')
|
|
31
|
-
expect(bankTransfer.paymentMeansCode).toBe('03')
|
|
32
|
-
expect(bankTransfer.payeeFinancialAccountID).toBe('ACC123')
|
|
33
|
-
expect(bankTransfer.paymentDueDate).toBe('2025-02-01')
|
|
34
|
-
|
|
35
|
-
const net30 = PaymentHelpers.net(30, 'ACC456')
|
|
36
|
-
expect(net30.paymentMeansCode).toBe('03')
|
|
37
|
-
expect(net30.paymentTerms).toBe('Net 30 days')
|
|
38
|
-
expect(net30.payeeFinancialAccountID).toBe('ACC456')
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should calculate taxes correctly', () => {
|
|
42
|
-
const sstResult = TaxHelpers.calculateSST(1000, 6)
|
|
43
|
-
expect(sstResult.taxAmount).toBe(60)
|
|
44
|
-
expect(sstResult.totalWithTax).toBe(1060)
|
|
45
|
-
|
|
46
|
-
const zeroRated = TaxHelpers.zeroRated(1000)
|
|
47
|
-
expect(zeroRated.taxAmount).toBe(0)
|
|
48
|
-
expect(zeroRated.totalWithTax).toBe(1000)
|
|
49
|
-
|
|
50
|
-
const exempt = TaxHelpers.exempt(1000)
|
|
51
|
-
expect(exempt.taxAmount).toBe(0)
|
|
52
|
-
expect(exempt.totalWithTax).toBe(1000)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('should create allowances and charges', () => {
|
|
56
|
-
const discount = AllowanceChargeHelpers.discount('Early payment', 100, 10)
|
|
57
|
-
expect(discount.chargeIndicator).toBe(false)
|
|
58
|
-
expect(discount.reason).toBe('Early payment')
|
|
59
|
-
expect(discount.amount).toBe(100)
|
|
60
|
-
expect(discount.multiplierFactorNumeric).toBe(0.1)
|
|
61
|
-
|
|
62
|
-
const shipping = AllowanceChargeHelpers.shipping(50)
|
|
63
|
-
expect(shipping.chargeIndicator).toBe(true)
|
|
64
|
-
expect(shipping.reason).toBe('Shipping and handling')
|
|
65
|
-
expect(shipping.amount).toBe(50)
|
|
66
|
-
|
|
67
|
-
const earlyDiscount = AllowanceChargeHelpers.earlyPaymentDiscount(2, 5000)
|
|
68
|
-
expect(earlyDiscount.chargeIndicator).toBe(false)
|
|
69
|
-
expect(earlyDiscount.amount).toBe(100) // 2% of 5000
|
|
70
|
-
expect(earlyDiscount.baseAmount).toBe(5000)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('should create delivery information', () => {
|
|
74
|
-
const standardDelivery = DeliveryHelpers.standard('2025-01-15', {
|
|
75
|
-
addressLine0: '123 Main St',
|
|
76
|
-
cityName: 'Kuala Lumpur',
|
|
77
|
-
postalZone: '50000',
|
|
78
|
-
state: '14',
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
expect(standardDelivery.actualDeliveryDate).toBe('2025-01-15')
|
|
82
|
-
expect(standardDelivery.deliveryLocation?.addressLine0).toBe(
|
|
83
|
-
'123 Main St',
|
|
84
|
-
)
|
|
85
|
-
expect(standardDelivery.deliveryLocation?.country).toBe('MYS')
|
|
86
|
-
|
|
87
|
-
const pickup = DeliveryHelpers.pickup('2025-01-16')
|
|
88
|
-
expect(pickup.actualDeliveryDate).toBe('2025-01-16')
|
|
89
|
-
expect(pickup.deliveryLocation?.addressLine0).toBe('Customer pickup')
|
|
90
|
-
|
|
91
|
-
const withFreight = DeliveryHelpers.withFreight(
|
|
92
|
-
'2025-01-17',
|
|
93
|
-
{
|
|
94
|
-
addressLine0: '456 Business Ave',
|
|
95
|
-
cityName: 'Shah Alam',
|
|
96
|
-
state: '10',
|
|
97
|
-
},
|
|
98
|
-
75,
|
|
99
|
-
'Express delivery',
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
expect(withFreight.shipment?.freightAllowanceCharge?.amount).toBe(75)
|
|
103
|
-
expect(withFreight.shipment?.freightAllowanceCharge?.reason).toBe(
|
|
104
|
-
'Express delivery',
|
|
105
|
-
)
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('should create document references', () => {
|
|
109
|
-
const po = DocumentReferenceHelpers.purchaseOrder('PO-2025-001')
|
|
110
|
-
expect(po.purchaseOrderReference).toBe('PO-2025-001')
|
|
111
|
-
|
|
112
|
-
const contract = DocumentReferenceHelpers.contract('CONTRACT-2025-001')
|
|
113
|
-
expect(contract.contractReference).toBe('CONTRACT-2025-001')
|
|
114
|
-
|
|
115
|
-
const customs = DocumentReferenceHelpers.customs('CUSTOMS-12345')
|
|
116
|
-
expect(customs.id).toBe('CUSTOMS-12345')
|
|
117
|
-
expect(customs.documentType).toBe('CustomsImportForm')
|
|
118
|
-
|
|
119
|
-
const fta = DocumentReferenceHelpers.freeTradeAgreement(
|
|
120
|
-
'FTA-123',
|
|
121
|
-
'Singapore',
|
|
122
|
-
)
|
|
123
|
-
expect(fta.id).toBe('FTA-123')
|
|
124
|
-
expect(fta.documentType).toBe('FreeTradeAgreement')
|
|
125
|
-
expect(fta.documentDescription).toBe(
|
|
126
|
-
'Free trade agreement with Singapore',
|
|
127
|
-
)
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
it('should provide industry classifications', () => {
|
|
131
|
-
expect(IndustryHelpers.software.industryClassificationCode).toBe('62012')
|
|
132
|
-
expect(IndustryHelpers.software.industryClassificationDescription).toBe(
|
|
133
|
-
'Business and domestic software development',
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
expect(IndustryHelpers.trading.industryClassificationCode).toBe('47900')
|
|
137
|
-
expect(IndustryHelpers.manufacturing.industryClassificationCode).toBe(
|
|
138
|
-
'10131',
|
|
139
|
-
)
|
|
140
|
-
expect(IndustryHelpers.consulting.industryClassificationCode).toBe(
|
|
141
|
-
'70200',
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
const custom = IndustryHelpers.custom('99999', 'Custom business activity')
|
|
145
|
-
expect(custom.industryClassificationCode).toBe('99999')
|
|
146
|
-
expect(custom.industryClassificationDescription).toBe(
|
|
147
|
-
'Custom business activity',
|
|
148
|
-
)
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('should handle currency exchange rates', () => {
|
|
152
|
-
const domestic = CurrencyHelpers.domestic()
|
|
153
|
-
expect(domestic.sourceCurrencyCode).toBe('MYR')
|
|
154
|
-
expect(domestic.targetCurrencyCode).toBe('MYR')
|
|
155
|
-
expect(domestic.calculationRate).toBe(1.0)
|
|
156
|
-
|
|
157
|
-
const international = CurrencyHelpers.international(
|
|
158
|
-
'USD',
|
|
159
|
-
'MYR',
|
|
160
|
-
4.75,
|
|
161
|
-
'2025-01-01',
|
|
162
|
-
)
|
|
163
|
-
expect(international.sourceCurrencyCode).toBe('USD')
|
|
164
|
-
expect(international.targetCurrencyCode).toBe('MYR')
|
|
165
|
-
expect(international.calculationRate).toBe(4.75)
|
|
166
|
-
expect(international.exchangeRateDate).toBe('2025-01-01')
|
|
167
|
-
|
|
168
|
-
// Test common rates
|
|
169
|
-
expect(CurrencyHelpers.commonRates.USD_MYR).toBe(4.75)
|
|
170
|
-
expect(CurrencyHelpers.commonRates.SGD_MYR).toBe(3.45)
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
it('should handle date and time formatting', () => {
|
|
174
|
-
const currentDate = DateTimeHelpers.currentDate()
|
|
175
|
-
expect(currentDate).toMatch(/^\d{4}-\d{2}-\d{2}$/)
|
|
176
|
-
|
|
177
|
-
const currentTime = DateTimeHelpers.currentTime()
|
|
178
|
-
expect(currentTime).toMatch(/^\d{2}:\d{2}:\d{2}Z$/)
|
|
179
|
-
|
|
180
|
-
const testDate = new Date('2025-01-15T10:30:00Z')
|
|
181
|
-
expect(DateTimeHelpers.formatDate(testDate)).toBe('2025-01-15')
|
|
182
|
-
expect(DateTimeHelpers.formatTime(testDate)).toBe('10:30:00Z')
|
|
183
|
-
|
|
184
|
-
const addedDays = DateTimeHelpers.addDays(testDate, 5)
|
|
185
|
-
expect(DateTimeHelpers.formatDate(addedDays)).toBe('2025-01-20')
|
|
186
|
-
|
|
187
|
-
const monthlyPeriod = DateTimeHelpers.monthlyPeriod(2025, 1)
|
|
188
|
-
expect(monthlyPeriod.start).toBe('2025-01-01')
|
|
189
|
-
expect(monthlyPeriod.end).toBe('2025-01-31')
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
it('should create invoice templates', () => {
|
|
193
|
-
const cashInvoice = InvoiceBuilder.basicCash('INV-CASH-001')
|
|
194
|
-
expect(cashInvoice.eInvoiceCodeOrNumber).toBe('INV-CASH-001')
|
|
195
|
-
expect(cashInvoice.eInvoiceTypeCode).toBe('01')
|
|
196
|
-
expect(cashInvoice.invoiceCurrencyCode).toBe('MYR')
|
|
197
|
-
expect(cashInvoice.paymentMeans?.[0].paymentMeansCode).toBe('01')
|
|
198
|
-
|
|
199
|
-
const businessInvoice = InvoiceBuilder.businessInvoice(
|
|
200
|
-
'INV-BIZ-001',
|
|
201
|
-
'ACC123',
|
|
202
|
-
30,
|
|
203
|
-
)
|
|
204
|
-
expect(businessInvoice.eInvoiceCodeOrNumber).toBe('INV-BIZ-001')
|
|
205
|
-
expect(businessInvoice.paymentMeans?.[0].paymentMeansCode).toBe('03')
|
|
206
|
-
expect(businessInvoice.paymentMeans?.[0].paymentTerms).toBe('Net 30 days')
|
|
207
|
-
|
|
208
|
-
const internationalInvoice = InvoiceBuilder.international(
|
|
209
|
-
'INV-USD-001',
|
|
210
|
-
'USD',
|
|
211
|
-
4.75,
|
|
212
|
-
)
|
|
213
|
-
expect(internationalInvoice.eInvoiceCodeOrNumber).toBe('INV-USD-001')
|
|
214
|
-
expect(internationalInvoice.invoiceCurrencyCode).toBe('USD')
|
|
215
|
-
expect(internationalInvoice.currencyExchangeRate).toBe(4.75)
|
|
216
|
-
expect(internationalInvoice.taxExchangeRate?.calculationRate).toBe(4.75)
|
|
217
|
-
})
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
describe('Validation Functions', () => {
|
|
221
|
-
const createTestInvoice = (): InvoiceV1_1 => ({
|
|
222
|
-
eInvoiceVersion: '1.1',
|
|
223
|
-
eInvoiceTypeCode: '01',
|
|
224
|
-
eInvoiceCodeOrNumber: 'TEST-001',
|
|
225
|
-
eInvoiceDate: '2025-01-01',
|
|
226
|
-
eInvoiceTime: '10:00:00Z',
|
|
227
|
-
invoiceCurrencyCode: 'MYR',
|
|
228
|
-
|
|
229
|
-
supplier: {
|
|
230
|
-
name: 'Test Supplier',
|
|
231
|
-
tin: 'C1234567890',
|
|
232
|
-
registrationType: 'BRN',
|
|
233
|
-
registrationNumber: '202201234567',
|
|
234
|
-
contactNumber: '+60123456789',
|
|
235
|
-
address: {
|
|
236
|
-
addressLine0: 'Test Address',
|
|
237
|
-
cityName: 'Kuala Lumpur',
|
|
238
|
-
state: '14',
|
|
239
|
-
country: 'MYS',
|
|
240
|
-
},
|
|
241
|
-
industryClassificationCode: '41001',
|
|
242
|
-
industryClassificationDescription: 'Test Industry',
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
buyer: {
|
|
246
|
-
name: 'Test Buyer',
|
|
247
|
-
tin: process.env.BUYER_TIN_VALUE || 'IG00000000000', // Replace with your buyer TIN
|
|
248
|
-
registrationType: 'NRIC',
|
|
249
|
-
registrationNumber: process.env.BUYER_NRIC_VALUE || '000000000000', // Replace with test NRIC
|
|
250
|
-
sstRegistrationNumber: 'NA',
|
|
251
|
-
contactNumber: '+60987654321',
|
|
252
|
-
address: {
|
|
253
|
-
addressLine0: 'Buyer Address',
|
|
254
|
-
cityName: 'Petaling Jaya',
|
|
255
|
-
state: '10',
|
|
256
|
-
country: 'MYS',
|
|
257
|
-
},
|
|
258
|
-
},
|
|
259
|
-
|
|
260
|
-
invoiceLineItems: [
|
|
261
|
-
{
|
|
262
|
-
itemClassificationCode: '001',
|
|
263
|
-
itemDescription: 'Test Product',
|
|
264
|
-
unitPrice: 100.0,
|
|
265
|
-
taxType: '01',
|
|
266
|
-
taxRate: 6.0,
|
|
267
|
-
taxAmount: 6.0,
|
|
268
|
-
totalTaxableAmountPerLine: 100.0,
|
|
269
|
-
totalAmountPerLine: 106.0,
|
|
270
|
-
},
|
|
271
|
-
],
|
|
272
|
-
|
|
273
|
-
legalMonetaryTotal: {
|
|
274
|
-
taxExclusiveAmount: 100.0,
|
|
275
|
-
taxInclusiveAmount: 106.0,
|
|
276
|
-
payableAmount: 106.0,
|
|
277
|
-
},
|
|
278
|
-
|
|
279
|
-
taxTotal: {
|
|
280
|
-
taxAmount: 6.0,
|
|
281
|
-
},
|
|
282
|
-
|
|
283
|
-
issuerDigitalSignature: {} as any,
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
it('should validate a correct invoice', () => {
|
|
287
|
-
const invoice = createTestInvoice()
|
|
288
|
-
const validation = validateInvoice(invoice)
|
|
289
|
-
|
|
290
|
-
expect(validation.isValid).toBe(true)
|
|
291
|
-
expect(validation.errors).toHaveLength(0)
|
|
292
|
-
expect(validation.warnings).toHaveLength(0)
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
it('should detect TIN format issues', () => {
|
|
296
|
-
const invoice = createTestInvoice()
|
|
297
|
-
invoice.supplier.tin = 'IG1234567890' // Individual TIN for company
|
|
298
|
-
|
|
299
|
-
const validation = validateInvoice(invoice)
|
|
300
|
-
|
|
301
|
-
expect(
|
|
302
|
-
validation.warnings.some(w => w.code === 'TIN_FORMAT_INVALID'),
|
|
303
|
-
).toBe(true)
|
|
304
|
-
expect(
|
|
305
|
-
validation.warnings.some(w =>
|
|
306
|
-
w.message.includes('Company TIN should start with "C"'),
|
|
307
|
-
),
|
|
308
|
-
).toBe(true)
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
it('should detect invalid contact numbers', () => {
|
|
312
|
-
const invoice = createTestInvoice()
|
|
313
|
-
invoice.supplier.contactNumber = 'invalid-phone'
|
|
314
|
-
|
|
315
|
-
const validation = validateInvoice(invoice)
|
|
316
|
-
|
|
317
|
-
expect(validation.isValid).toBe(false)
|
|
318
|
-
expect(
|
|
319
|
-
validation.errors.some(e => e.code === 'CONTACT_FORMAT_INVALID'),
|
|
320
|
-
).toBe(true)
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
it('should detect tax calculation mismatches', () => {
|
|
324
|
-
const invoice = createTestInvoice()
|
|
325
|
-
invoice.taxTotal.taxAmount = 10.0 // Wrong tax amount
|
|
326
|
-
|
|
327
|
-
const validation = validateInvoice(invoice)
|
|
328
|
-
|
|
329
|
-
expect(validation.isValid).toBe(false)
|
|
330
|
-
expect(
|
|
331
|
-
validation.errors.some(e => e.code === 'TAX_AMOUNT_MISMATCH'),
|
|
332
|
-
).toBe(true)
|
|
333
|
-
})
|
|
334
|
-
|
|
335
|
-
it('should detect negative amounts', () => {
|
|
336
|
-
const invoice = createTestInvoice()
|
|
337
|
-
invoice.legalMonetaryTotal.payableAmount = -100
|
|
338
|
-
|
|
339
|
-
const validation = validateInvoice(invoice)
|
|
340
|
-
|
|
341
|
-
expect(validation.isValid).toBe(false)
|
|
342
|
-
expect(validation.errors.some(e => e.code === 'AMOUNT_NEGATIVE')).toBe(
|
|
343
|
-
true,
|
|
344
|
-
)
|
|
345
|
-
})
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
describe('Enhanced Document Generation', () => {
|
|
349
|
-
it('should generate document with dynamic industry classification', () => {
|
|
350
|
-
const invoice = createBasicInvoiceWithIndustry()
|
|
351
|
-
|
|
352
|
-
// Test clean document generation without signing (avoids crypto errors with dummy keys)
|
|
353
|
-
const cleanDocument = generateCleanUBLDocument([invoice])
|
|
354
|
-
|
|
355
|
-
expect(cleanDocument.Invoice).toHaveLength(1)
|
|
356
|
-
expect(cleanDocument.Invoice[0].AccountingSupplierParty).toBeDefined()
|
|
357
|
-
})
|
|
358
|
-
|
|
359
|
-
it('should generate document with dynamic delivery information', () => {
|
|
360
|
-
const invoice = createInvoiceWithDelivery()
|
|
361
|
-
|
|
362
|
-
// Test clean document generation without signing (avoids crypto errors with dummy keys)
|
|
363
|
-
const cleanDocument = generateCleanUBLDocument([invoice])
|
|
364
|
-
|
|
365
|
-
expect(
|
|
366
|
-
cleanDocument.Invoice[0].AccountingSupplierParty[0].Party[0]
|
|
367
|
-
.PostalAddress[0].CityName[0]._,
|
|
368
|
-
).toBe('Shah Alam')
|
|
369
|
-
})
|
|
370
|
-
})
|
|
371
|
-
})
|
|
372
|
-
|
|
373
|
-
// Helper functions for creating test invoices with specific features
|
|
374
|
-
|
|
375
|
-
function createBasicInvoiceWithIndustry(): InvoiceV1_1 {
|
|
376
|
-
const baseInvoice = InvoiceBuilder.basicCash('TEST-INDUSTRY-001')
|
|
377
|
-
|
|
378
|
-
return {
|
|
379
|
-
...baseInvoice,
|
|
380
|
-
supplier: {
|
|
381
|
-
name: 'Software Co Sdn Bhd',
|
|
382
|
-
tin: 'C1234567890',
|
|
383
|
-
registrationType: 'BRN',
|
|
384
|
-
registrationNumber: '202201234567',
|
|
385
|
-
contactNumber: '+60123456789',
|
|
386
|
-
...IndustryHelpers.software, // Dynamic industry classification
|
|
387
|
-
address: {
|
|
388
|
-
addressLine0: 'Tech Hub',
|
|
389
|
-
cityName: 'Kuala Lumpur',
|
|
390
|
-
postalZone: '50000',
|
|
391
|
-
state: '14',
|
|
392
|
-
country: 'MYS',
|
|
393
|
-
},
|
|
394
|
-
},
|
|
395
|
-
buyer: {
|
|
396
|
-
name: 'Test Buyer',
|
|
397
|
-
tin: 'EI00000000010',
|
|
398
|
-
registrationType: 'NRIC',
|
|
399
|
-
registrationNumber: process.env.BUYER_NRIC_VALUE || '000000000000', // Replace with test NRIC
|
|
400
|
-
sstRegistrationNumber: 'NA',
|
|
401
|
-
contactNumber: '+60123456789',
|
|
402
|
-
address: {
|
|
403
|
-
addressLine0: 'Buyer Address',
|
|
404
|
-
cityName: 'KL',
|
|
405
|
-
postalZone: '50000',
|
|
406
|
-
state: '14',
|
|
407
|
-
country: 'MYS',
|
|
408
|
-
},
|
|
409
|
-
},
|
|
410
|
-
invoiceLineItems: [
|
|
411
|
-
{
|
|
412
|
-
itemClassificationCode: '001',
|
|
413
|
-
itemDescription: 'Software Services',
|
|
414
|
-
unitPrice: 1000.0,
|
|
415
|
-
quantity: 1,
|
|
416
|
-
measurement: 'C62',
|
|
417
|
-
taxType: '01',
|
|
418
|
-
taxRate: 6.0,
|
|
419
|
-
taxAmount: 60.0,
|
|
420
|
-
totalTaxableAmountPerLine: 1000.0,
|
|
421
|
-
totalAmountPerLine: 1060.0,
|
|
422
|
-
},
|
|
423
|
-
],
|
|
424
|
-
legalMonetaryTotal: {
|
|
425
|
-
taxExclusiveAmount: 1000.0,
|
|
426
|
-
taxInclusiveAmount: 1060.0,
|
|
427
|
-
payableAmount: 1060.0,
|
|
428
|
-
},
|
|
429
|
-
taxTotal: {
|
|
430
|
-
taxAmount: 60.0,
|
|
431
|
-
taxSubtotals: [
|
|
432
|
-
{
|
|
433
|
-
taxableAmount: 1000.0,
|
|
434
|
-
taxAmount: 60.0,
|
|
435
|
-
taxCategory: {
|
|
436
|
-
taxTypeCode: '01',
|
|
437
|
-
taxRate: 6.0,
|
|
438
|
-
},
|
|
439
|
-
},
|
|
440
|
-
],
|
|
441
|
-
},
|
|
442
|
-
issuerDigitalSignature: {} as any,
|
|
443
|
-
} as InvoiceV1_1
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function createInvoiceWithDelivery(): InvoiceV1_1 {
|
|
447
|
-
const invoice = createBasicInvoiceWithIndustry()
|
|
448
|
-
// Update supplier address to Shah Alam as expected by the test
|
|
449
|
-
invoice.supplier.address.cityName = 'Shah Alam'
|
|
450
|
-
return invoice
|
|
451
|
-
}
|