🚀 Initialize Musadaq SaaS: Full Backend + AI + React Dashboard + Docker Setup
This commit is contained in:
93
backend/src/modules/invoices/ubl-generator.service.ts
Normal file
93
backend/src/modules/invoices/ubl-generator.service.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* ════════════════════════════════════════════════════════════
|
||||
* مُصادَق (Musadaq) — UBL 2.1 Generator Service
|
||||
* ════════════════════════════════════════════════════════════
|
||||
* يقوم بإنشاء ملفات XML المتوافقة مع معيار UBL 2.1 المطلوبة من
|
||||
* دائرة ضريبة الدخل والمبيعات الأردنية (ISTD).
|
||||
* ════════════════════════════════════════════════════════════
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { create } from 'xmlbuilder2';
|
||||
import { Invoice } from './entities/invoice.entity';
|
||||
|
||||
@Injectable()
|
||||
export class UBLGeneratorService {
|
||||
/**
|
||||
* توليد UBL 2.1 XML لفاتورة مبيعات
|
||||
*/
|
||||
generateXML(invoice: Invoice, company: any): string {
|
||||
const doc = create({ version: '1.0', encoding: 'UTF-8' })
|
||||
.ele('Invoice', {
|
||||
xmlns: 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2',
|
||||
'xmlns:cac': 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2',
|
||||
'xmlns:cbc': 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2',
|
||||
})
|
||||
.ele('cbc:UBLVersionID').txt('2.1').up()
|
||||
.ele('cbc:CustomizationID').txt('TRX-1.0').up()
|
||||
.ele('cbc:ID').txt(invoice.invoice_number || 'N/A').up()
|
||||
.ele('cbc:IssueDate').txt(invoice.invoice_date?.toISOString().split('T')[0] || '').up()
|
||||
.ele('cbc:InvoiceTypeCode').txt(invoice.ubl_type_code).up()
|
||||
.ele('cbc:DocumentCurrencyCode').txt(invoice.currency_code).up()
|
||||
|
||||
// ── AccountingSupplierParty (المُصدر) ───────────────
|
||||
.ele('cac:AccountingSupplierParty')
|
||||
.ele('cac:Party')
|
||||
.ele('cac:PartyIdentification')
|
||||
.ele('cbc:ID').txt(company.tax_identification_number).up()
|
||||
.up()
|
||||
.ele('cac:PartyName')
|
||||
.ele('cbc:Name').txt(company.name).up()
|
||||
.up()
|
||||
.ele('cac:PostalAddress')
|
||||
.ele('cbc:StreetName').txt(company.address || '').up()
|
||||
.ele('cac:Country')
|
||||
.ele('cbc:IdentificationCode').txt('JO').up()
|
||||
.up()
|
||||
.up()
|
||||
.up()
|
||||
.up()
|
||||
|
||||
// ── AccountingCustomerParty (المشتري) ───────────────
|
||||
.ele('cac:AccountingCustomerParty')
|
||||
.ele('cac:Party')
|
||||
.ele('cac:PartyIdentification')
|
||||
.ele('cbc:ID').txt(invoice.buyer_tin || invoice.buyer_national_id || '').up()
|
||||
.up()
|
||||
.ele('cac:PartyName')
|
||||
.ele('cbc:Name').txt(invoice.buyer_name || '').up()
|
||||
.up()
|
||||
.up()
|
||||
.up()
|
||||
|
||||
// ── TaxTotal ───────────────────────────────────────
|
||||
.ele('cac:TaxTotal')
|
||||
.ele('cbc:TaxAmount', { currencyID: invoice.currency_code }).txt(invoice.tax_amount.toString()).up()
|
||||
.up()
|
||||
|
||||
// ── LegalMonetaryTotal ─────────────────────────────
|
||||
.ele('cac:LegalMonetaryTotal')
|
||||
.ele('cbc:LineExtensionAmount', { currencyID: invoice.currency_code }).txt(invoice.subtotal.toString()).up()
|
||||
.ele('cbc:TaxExclusiveAmount', { currencyID: invoice.currency_code }).txt(invoice.subtotal.toString()).up()
|
||||
.ele('cbc:TaxInclusiveAmount', { currencyID: invoice.currency_code }).txt(invoice.grand_total.toString()).up()
|
||||
.ele('cbc:PayableAmount', { currencyID: invoice.currency_code }).txt(invoice.grand_total.toString()).up()
|
||||
.up();
|
||||
|
||||
// ── InvoiceLines ─────────────────────────────────────
|
||||
invoice.lines.forEach((line) => {
|
||||
doc.ele('cac:InvoiceLine')
|
||||
.ele('cbc:ID').txt(line.line_number.toString()).up()
|
||||
.ele('cbc:InvoicedQuantity', { unitCode: 'PCE' }).txt(line.quantity.toString()).up()
|
||||
.ele('cbc:LineExtensionAmount', { currencyID: invoice.currency_code }).txt(line.line_total.toString()).up()
|
||||
.ele('cac:Item')
|
||||
.ele('cbc:Description').txt(line.description).up()
|
||||
.up()
|
||||
.ele('cac:Price')
|
||||
.ele('cbc:PriceAmount', { currencyID: invoice.currency_code }).txt(line.unit_price.toString()).up()
|
||||
.up()
|
||||
.up();
|
||||
});
|
||||
|
||||
return doc.end({ prettyPrint: true });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user