Skip to content

Commit

Permalink
Merge pull request #5 from wes4m/dev
Browse files Browse the repository at this point in the history
Experimental release v0.1.1 release
  • Loading branch information
wes4m authored Sep 23, 2022
2 parents 242fc60 + 4a9e7a6 commit 0790a69
Show file tree
Hide file tree
Showing 7 changed files with 21 additions and 26 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const egsunit: EGSUnitInfo = {/*...*/};
// Init EGS unit
const egs = new EGS(egsunit);
// New Keys & CSR for the EGS
await egs.generateNewKeysAndCSR(false);
await egs.generateNewKeysAndCSR(false, "solution_name");
// Issue a new compliance cert for the EGS
const compliance_rid = await egs.issueComplianceCertificate("123345");
// Sign invoice
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "zatca-xml-js",
"version": "0.1.0",
"version": "0.1.1",
"description": "An implementation of Saudi Arabia ZATCA's E-Invocing requirements, processes, and standards.",
"main": "lib/index.js",
"files": ["lib/**/*"],
"scripts": {
"build": "tsc --project tsconfig.build.json",
"test": "tsc && node testing_lib/tests/test.js",
"example": "tsc && node lib/examples/full.js",
"example": "tsc --project tsconfig.build.json && node lib/examples/full.js",
"prepare": "npm run build"
},
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/examples/full.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const main = async () => {
const egs = new EGS(egsunit);

// New Keys & CSR for the EGS
await egs.generateNewKeysAndCSR(false);
await egs.generateNewKeysAndCSR(false, "solution_name");

// Issue a new compliance cert for the EGS
const compliance_request_id = await egs.issueComplianceCertificate("123345");
Expand Down
23 changes: 9 additions & 14 deletions src/zatca/ZATCASimplifiedTaxInvoice.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { XMLDocument } from "../parser";
import { generateSignedXMLString } from "./signing";
import defaultSimplifiedTaxInvoice, { ZATCASimplifiedInvoiceLineItem, ZATCASimplifiedInvoiceProps } from "./templates/simplified_tax_invoice_template";

export {ZATCASimplifiedInvoiceLineItem, ZATCASimplifiedInvoiceProps};
import defaultSimplifiedTaxInvoice, {
ZATCASimplifiedInvoiceLineItem,
ZATCASimplifiedInvoiceProps,
ZATCAInvoiceTypes,
ZATCAPaymentMethods
} from "./templates/simplified_tax_invoice_template";

export {ZATCASimplifiedInvoiceLineItem, ZATCASimplifiedInvoiceProps, ZATCAInvoiceTypes, ZATCAPaymentMethods};
export class ZATCASimplifiedTaxInvoice {

private invoice_xml: XMLDocument;
Expand All @@ -29,8 +34,6 @@ export class ZATCASimplifiedTaxInvoice {
}

private constructLineItemTotals = (line_item: ZATCASimplifiedInvoiceLineItem) => {

// TODO: decimal fixing according to ZATCA

let line_item_total_discounts = 0;
let line_item_total_taxes = 0;
Expand Down Expand Up @@ -121,32 +124,25 @@ export class ZATCASimplifiedTaxInvoice {

return {
line_item_xml: {
// .. TODO
"cbc:ID": line_item.id,
// .. TODO
"cbc:InvoicedQuantity": {
"@_unitCode": "PCE",
"#text": line_item.quantity
},
// .. TODO
"cbc:LineExtensionAmount": {
"@_currencyID": "SAR",
"#text": line_item_total_tax_exclusive
},
// .. TODO
"cac:TaxTotal": cacTaxTotal,
// .. TODO
"cac:Item": {
"cbc:Name": line_item.name,
"cac:ClassifiedTaxCategory": cacClassifiedTaxCategories
},
// .. TODO
"cac:Price": {
"cbc:PriceAmount": {
"@_currencyID": "SAR",
"#text": line_item.tax_exclusive_price
},
// .. TODO
"cac:AllowanceCharge": cacAllowanceCharges
}
},
Expand All @@ -161,7 +157,6 @@ export class ZATCASimplifiedTaxInvoice {

private constructLegalMonetaryTotal = (tax_exclusive_subtotal: number, taxes_total: number) => {

// TODO: amount decimals according to ZATCA
return {
"cbc:LineExtensionAmount": {
"@_currencyID": "SAR",
Expand Down Expand Up @@ -276,7 +271,7 @@ export class ZATCASimplifiedTaxInvoice {


if(props.cancelation) {
// Invoice canceled. Make it a credit/debit note
// Invoice canceled. Tunred into credit/debit note. Must have PaymentMeans
// BR-KSA-17
this.invoice_xml.set("Invoice/cac:PaymentMeans", false, {
"cbc:PaymentMeansCode": props.cancelation.payment_method,
Expand Down
1 change: 0 additions & 1 deletion src/zatca/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import axios from "axios";
import { cleanUpCertificateString } from "../signing";
import { ZATCASimplifiedTaxInvoice } from "../ZATCASimplifiedTaxInvoice";


const settings = {
Expand Down
11 changes: 6 additions & 5 deletions src/zatca/egs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const generateSecp256k1KeyPair = async (): Promise<string> => {

// Generate a signed ecdsaWithSHA256 CSR
// 2.2.2 Profile specification of the Cryptographic Stamp identifiers. & CSR field contents / RDNs.
const generateCSR = async (egs_info: EGSUnitInfo, production: boolean): Promise<string> => {
const generateCSR = async (egs_info: EGSUnitInfo, production: boolean, solution_name: string): Promise<string> => {
if (!egs_info.private_key) throw new Error("EGS has no private key");

// This creates a temporary private file, and csr config file to pass to OpenSSL in order to create and sign the CSR.
Expand All @@ -90,7 +90,7 @@ const generateCSR = async (egs_info: EGSUnitInfo, production: boolean): Promise<
fs.writeFileSync(csr_config_file, defaultCSRConfig({
egs_model: egs_info.model,
egs_serial_number: egs_info.uuid,
solution_name: "TODONAME",
solution_name: solution_name,
vat_number: egs_info.VAT_number,
branch_location: `${egs_info.location.building} ${egs_info.location.street}, ${egs_info.location.city}`,
branch_industry: egs_info.branch_industry,
Expand Down Expand Up @@ -151,15 +151,16 @@ export class EGS {
* Generates a new secp256k1 Public/Private key pair for the EGS.
* Also generates and signs a new CSR.
* `Note`: This functions uses OpenSSL thus requires it to be installed on whatever system the package is running in.
* @param Boolean Production CSR or Compliance CSR
* @param production Boolean CSR or Compliance CSR
* @param solution_name String name of solution generating certs.
* @returns Promise void on success, throws error on fail.
*/
async generateNewKeysAndCSR(production: boolean): Promise<any> {
async generateNewKeysAndCSR(production: boolean, solution_name: string): Promise<any> {
try {
const new_private_key = await generateSecp256k1KeyPair();
this.egs_info.private_key = new_private_key;

const new_csr = await generateCSR(this.egs_info, production);
const new_csr = await generateCSR(this.egs_info, production, solution_name);
this.egs_info.csr = new_csr;
} catch (error) {
throw error;
Expand Down
4 changes: 2 additions & 2 deletions src/zatca/templates/simplified_tax_invoice_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export interface ZATCASimplifiedInvoiceLineItem {
export interface ZATCASimplifiedInvoicCancelation{
canceled_invoice_number: number,
payment_method: ZATCAPaymentMethods,
cancelation_type: ZATCAInvoiceTypes,
reason: string
}

Expand All @@ -126,8 +127,7 @@ export interface ZATCASimplifiedInvoiceProps {
export default function populate(props: ZATCASimplifiedInvoiceProps): string {
let populated_template = template;

// TODO Debit or Credit selection
populated_template = populated_template.replace("SET_INVOICE_TYPE", props.cancelation ? ZATCAInvoiceTypes.CREDIT_NOTE : ZATCAInvoiceTypes.INVOICE);
populated_template = populated_template.replace("SET_INVOICE_TYPE", props.cancelation ? props.cancelation.cancelation_type : ZATCAInvoiceTypes.INVOICE);
// if canceled (BR-KSA-56) set reference number to canceled invoice
if(props.cancelation) {
populated_template = populated_template.replace("SET_BILLING_REFERENCE", defaultBillingReference(props.cancelation.canceled_invoice_number));
Expand Down

0 comments on commit 0790a69

Please sign in to comment.