From 6a48f203a945b6a29166b63491023aaeecb89b12 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Mon, 4 May 2026 11:21:49 +0330 Subject: [PATCH] set invoke in nama --- .vscode/settings.json | 9 +- prisma/schema/shared/enum.prisma | 3 +- src/generated/prisma/enums.ts | 5 +- src/generated/prisma/internal/class.ts | 2 +- src/main.ts | 3 + .../saleInvoices/saleInvoices.module.ts | 15 +- .../utils/getPartnerRemainingLicenses.util.ts | 13 +- .../sales-invoices.controller.ts | 5 + .../sales-invoices/sales-invoices.module.ts | 14 +- .../sales-invoices/sales-invoices.service.ts | 8 + .../tspProviders/dto/provider-switch.dto.ts | 72 ++++++ .../sales-invoice-tsp-switch.service.ts | 9 + .../tspProviders/sales-invoice-tsp.module.ts | 26 ++ .../tspProviders/sales-invoice-tsp.service.ts | 185 +++++++++++++- .../switch/nama/nama-provider.adapter.ts | 227 +++++------------- .../switch/nama/nama-provider.dto.ts | 160 ++++++++++-- .../switch/nama/nama-provider.util.ts | 195 +++++++++++++++ 17 files changed, 711 insertions(+), 240 deletions(-) create mode 100644 src/modules/tspProviders/sales-invoice-tsp.module.ts create mode 100644 src/modules/tspProviders/switch/nama/nama-provider.util.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index be9ce0e..6b7731b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,9 +16,16 @@ "ARVANCLOUD", "autoincrement", "Cardex", + "consfee", "fkey", "iban", + "indatim", "inno", - "MAYKET" + "inty", + "irtaxid", + "MAYKET", + "setm", + "spro", + "sstid" ] } diff --git a/prisma/schema/shared/enum.prisma b/prisma/schema/shared/enum.prisma index 528f86d..9bb32fc 100644 --- a/prisma/schema/shared/enum.prisma +++ b/prisma/schema/shared/enum.prisma @@ -167,13 +167,14 @@ enum TspProviderResponseStatus { FAILURE NOT_SEND QUEUED + REVOKED } enum TspProviderRequestType { MAIN UPDATE REVOKE - REMOVE + RETURN } enum TspProviderCustomerType { diff --git a/src/generated/prisma/enums.ts b/src/generated/prisma/enums.ts index c6567e4..b032ca8 100644 --- a/src/generated/prisma/enums.ts +++ b/src/generated/prisma/enums.ts @@ -261,7 +261,8 @@ export const TspProviderResponseStatus = { SUCCESS: 'SUCCESS', FAILURE: 'FAILURE', NOT_SEND: 'NOT_SEND', - QUEUED: 'QUEUED' + QUEUED: 'QUEUED', + REVOKED: 'REVOKED' } as const export type TspProviderResponseStatus = (typeof TspProviderResponseStatus)[keyof typeof TspProviderResponseStatus] @@ -271,7 +272,7 @@ export const TspProviderRequestType = { MAIN: 'MAIN', UPDATE: 'UPDATE', REVOKE: 'REVOKE', - REMOVE: 'REMOVE' + RETURN: 'RETURN' } as const export type TspProviderRequestType = (typeof TspProviderRequestType)[keyof typeof TspProviderRequestType] diff --git a/src/generated/prisma/internal/class.ts b/src/generated/prisma/internal/class.ts index 02c0037..5af00ef 100644 --- a/src/generated/prisma/internal/class.ts +++ b/src/generated/prisma/internal/class.ts @@ -22,7 +22,7 @@ const config: runtime.GetPrismaClientConfig = { "clientVersion": "7.7.0", "engineVersion": "75cbdc1eb7150937890ad5465d861175c6624711", "activeProvider": "mysql", - "inlineSchema": "model AdminAccount {\n id String @id @default(ulid())\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n admin_id String\n admin Admin @relation(fields: [admin_id], references: [id])\n\n account_id String @unique\n account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)\n\n @@map(\"admin_accounts\")\n}\n\nmodel Admin {\n id String @id @default(ulid())\n mobile_number String @unique()\n national_code String? @unique()\n first_name String\n last_name String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n accounts AdminAccount[]\n\n @@map(\"admins\")\n}\n\n// model LegalProfile {\n// user_id String @id\n// company_name String\n// register_no String @unique()\n// representative_name String?\n// representative_national_id String?\n\n// // user User @relation(fields: [user_id], references: [id])\n\n// @@map(\"legal_profiles\")\n// }\n\n// model IndividualProfile {\n// user_id String @id\n// national_code String @unique()\n// first_name String\n// last_name String\n// birth_date DateTime?\n// mobile_number String\n// // user User @relation(fields: [user_id], references: [id])\n\n// @@map(\"individual_profiles\")\n// }\n\nmodel Account {\n id String @id @default(ulid())\n username String @unique()\n password String\n status AccountStatus\n type AccountType\n\n admin_account AdminAccount?\n provider_account ProviderAccount?\n partner_account PartnerAccount?\n consumer_account ConsumerAccount?\n\n // admin_account_id String? @unique\n // admin_account AdminAccount? @relation(fields: [admin_account_id], references: [id], onDelete: Cascade)\n\n // provider_account_id String? @unique\n // provider_account ProviderAccount? @relation(fields: [provider_account_id], references: [id], onDelete: Cascade)\n\n // partner_account_id String? @unique\n // partner_account PartnerAccount? @relation(fields: [partner_account_id], references: [id], onDelete: Cascade)\n\n // consumer_account_id String? @unique\n // consumer_account ConsumerAccount? @relation(fields: [consumer_account_id], references: [id], onDelete: Cascade)\n\n // tokens Token[]\n // refresh_tokens RefreshToken[]\n\n @@map(\"accounts\")\n}\n\n// model Token {\n// id String @id @d @uniqueefault(ulid())\n// token String @unique\n// type TokenType\n// created_at DateTime @default(now())\n// expires_at DateTime\n\n// account_id String\n// account Account @relation(fields: [account_id], references: [id])\n\n// @@unique([type, account_id])\n// @@map(\"tokens\")\n// }\n\n// model VerificationCode {\n// id String @id @default(ulid())\n// code String\n// is_used Boolean @default(false)\n// created_at DateTime @default(now())\n// expires_at DateTime\n\n// account_id String\n// account Account @relation(fields: [account_id], references: [id])\n\n// @@map(\"verification_codes\")\n// }\n\nmodel DeviceBrand {\n id String @id @default(ulid())\n name String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n devices Device[]\n\n @@map(\"device_brands\")\n}\n\nmodel Device {\n id String @id @default(ulid())\n name String\n os_version String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n brand_id String\n\n brand DeviceBrand @relation(fields: [brand_id], references: [id])\n poses Pos[]\n\n @@map(\"devices\")\n}\n\nmodel LicenseChargeTransaction {\n id String @id @default(ulid())\n activation_expires_at DateTime\n tracking_code String @unique()\n purchased_count Int\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n licenses License[]\n\n @@map(\"license_charged_transactions\")\n}\n\nmodel License {\n id String @id @default(ulid())\n accounts_limit Int @default(2)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n charge_transaction_id String\n charge_transaction LicenseChargeTransaction @relation(fields: [charge_transaction_id], references: [id])\n\n activation LicenseActivation?\n\n @@map(\"licenses\")\n}\n\nmodel LicenseActivation {\n id String @id @unique() @default(ulid())\n starts_at DateTime\n expires_at DateTime\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n license_id String @unique\n license License @relation(fields: [license_id], references: [id])\n\n business_activity_id String @unique\n business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])\n\n license_renews LicenseRenew[]\n account_allocations LicenseAccountAllocation[]\n\n @@map(\"licenses_activated\")\n}\n\nmodel LicenseRenewChargeTransaction {\n id String @id @default(ulid())\n activation_expires_at DateTime\n tracking_code String @unique()\n purchased_count Int\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n license_renews LicenseRenew[]\n\n @@map(\"license_renew_charge_transaction\")\n}\n\nmodel LicenseRenew {\n id String @id @default(ulid())\n expires_at DateTime\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n charge_transaction_id String\n charge_transaction LicenseRenewChargeTransaction @relation(fields: [charge_transaction_id], references: [id])\n\n activation_id String?\n activation LicenseActivation? @relation(fields: [activation_id], references: [id])\n\n @@map(\"license_renew\")\n}\n\nmodel PartnerAccountQuotaChargeTransaction {\n id String @id @default(ulid())\n activation_expires_at DateTime\n tracking_code String @unique()\n purchased_count Int\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n credits PartnerAccountQuotaCredit[]\n\n @@map(\"partner_account_quota_charge_transaction\")\n}\n\nmodel PartnerAccountQuotaCredit {\n id String @id @default(ulid())\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n charge_transaction_id String?\n charge_transaction PartnerAccountQuotaChargeTransaction? @relation(fields: [charge_transaction_id], references: [id])\n\n allocation LicenseAccountAllocation?\n\n @@map(\"partner_account_quota_credit\")\n}\n\nmodel LicenseAccountAllocation {\n id String @id @default(ulid())\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n license_activation_id String?\n license_activation LicenseActivation? @relation(fields: [license_activation_id], references: [id])\n\n account_id String? @unique\n account ConsumerAccount? @relation(fields: [account_id], references: [id])\n\n credit_id String? @unique\n credit PartnerAccountQuotaCredit? @relation(fields: [credit_id], references: [id])\n\n @@map(\"license_account_allocation\")\n}\n\nmodel PartnerAccount {\n id String @id @default(ulid())\n role PartnerRole\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n account_id String @unique\n account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)\n\n @@map(\"partner_accounts\")\n}\n\nmodel Partner {\n id String @id @default(ulid())\n name String\n code String @unique()\n status PartnerStatus @default(ACTIVE)\n tsp_provider TspProviderType @default(NAMA)\n logo_url String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)\n\n accounts PartnerAccount[]\n consumers_individual ConsumerIndividual[]\n consumers_legal ConsumerLegal[]\n license_charge_transactions LicenseChargeTransaction[]\n account_quota_charge_transactions PartnerAccountQuotaChargeTransaction[]\n license_renew_charge_transactions LicenseRenewChargeTransaction[]\n\n @@map(\"partners\")\n}\n\nmodel PermissionConsumer {\n id String @id @default(ulid())\n\n consumer_account_id String @unique\n consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id], onDelete: Cascade)\n\n pos_permissions PermissionPos[]\n complex_permissions PermissionComplex[]\n business_permissions PermissionBusiness[]\n\n @@map(\"permission_consumers\")\n}\n\nmodel PermissionPos {\n id String @id @default(ulid())\n role POSRole\n\n pos_id String\n permission_id String\n\n pos Pos @relation(fields: [pos_id], references: [id], onDelete: Cascade)\n permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)\n\n @@unique([permission_id, pos_id])\n @@map(\"permission_poses\")\n}\n\nmodel PermissionComplex {\n id String @id @default(ulid())\n role ComplexRole\n\n complex_id String\n permission_id String\n\n complex Complex @relation(fields: [complex_id], references: [id], onDelete: Cascade)\n permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)\n\n @@unique([permission_id, complex_id])\n @@map(\"permission_complexes\")\n}\n\nmodel PermissionBusiness {\n id String @id @default(ulid())\n role BusinessRole\n\n business_id String\n permission_id String\n\n business BusinessActivity @relation(fields: [business_id], references: [id], onDelete: Cascade)\n permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)\n\n @@unique([permission_id, business_id])\n @@map(\"permission_business_activities\")\n}\n\nmodel ProviderAccount {\n id String @id @default(ulid())\n role ProviderRole\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n provider_id String\n provider Provider @relation(fields: [provider_id], references: [id])\n\n account_id String @unique\n account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)\n\n @@map(\"provider_accounts\")\n}\n\nmodel Provider {\n id String @id @default(ulid())\n code String @unique()\n status PartnerStatus @default(ACTIVE)\n name String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n\n accounts ProviderAccount[]\n pos_list Pos[]\n\n @@map(\"providers\")\n}\n\nmodel ConsumerDevices {\n uuid String @id @unique() @db.VarChar(255)\n app_version String @db.VarChar(20)\n build_number String @db.VarChar(20)\n platform String @db.VarChar(100)\n brand String @db.VarChar(100)\n model String @db.VarChar(100)\n device String @db.VarChar(100)\n publisher ApplicationPublisher\n os_version String @db.VarChar(20)\n sdk_version String @db.VarChar(20)\n release_number String @db.VarChar(20)\n user_agent String? @db.VarChar(100)\n browser_name String? @db.VarChar(100)\n fcm_token String? @db.VarChar(100)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n consumer_id String\n consumer Consumer @relation(fields: [consumer_id], references: [id])\n\n @@map(\"consumer_devices\")\n}\n\nmodel ApplicationReleasedInfo {\n id String @id @default(ulid())\n version String\n build_number String\n is_minimum_supported Boolean @default(false)\n release_type ApplicationReleaseType\n platform ApplicationPlatform\n notes Json?\n\n release_date DateTime @default(now()) @db.Timestamp(0)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n @@map(\"application_released_info\")\n}\n\nmodel ConsumerAccount {\n id String @id @default(ulid())\n role ConsumerRole\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n consumer_id String\n consumer Consumer @relation(fields: [consumer_id], references: [id])\n\n account_id String @unique()\n account Account @relation(fields: [account_id], references: [id])\n\n pos Pos?\n permission PermissionConsumer?\n account_allocation LicenseAccountAllocation?\n sales_invoices SalesInvoice[]\n\n @@map(\"consumer_accounts\")\n}\n\nmodel Consumer {\n id String @id @default(ulid())\n type ConsumerType\n status ConsumerStatus @default(ACTIVE)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n accounts ConsumerAccount[]\n business_activities BusinessActivity[]\n devices ConsumerDevices[]\n individual ConsumerIndividual?\n legal ConsumerLegal?\n\n @@map(\"consumers\")\n}\n\nmodel ConsumerIndividual {\n first_name String\n last_name String\n mobile_number String\n national_code String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n consumer_id String @id\n consumer Consumer @relation(fields: [consumer_id], references: [id], onDelete: Cascade)\n\n @@unique([mobile_number, consumer_id])\n @@unique([partner_id, national_code])\n @@map(\"consumers_individual\")\n}\n\nmodel ConsumerLegal {\n name String\n registration_code String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n consumer_id String @id\n consumer Consumer @relation(fields: [consumer_id], references: [id], onDelete: Cascade)\n\n @@unique([partner_id, registration_code])\n @@map(\"consumers_legal\")\n}\n\nmodel BusinessActivity {\n id String @id @default(ulid())\n economic_code String\n name String\n fiscal_id String\n partner_token String\n invoice_number_sequence Decimal @default(1) @db.Decimal(20, 0)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n guild_id String\n guild Guild @relation(fields: [guild_id], references: [id])\n\n consumer_id String\n consumer Consumer @relation(fields: [consumer_id], references: [id])\n\n license_activation LicenseActivation?\n complexes Complex[]\n permission_businesses PermissionBusiness[]\n goods Good[]\n customer_individuals CustomerIndividual[]\n customer_legals CustomerLegal[]\n\n @@unique([economic_code, consumer_id])\n @@map(\"business_activities\")\n}\n\nmodel Complex {\n id String @id @default(ulid())\n name String\n branch_code String\n address String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n business_activity_id String\n\n business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])\n\n pos_list Pos[]\n good_categories GoodCategory[]\n permission_complexes PermissionComplex[]\n\n @@map(\"complexes\")\n}\n\nmodel Pos {\n id String @id @default(ulid())\n name String\n model String?\n serial_number String? @unique()\n status POSStatus @default(ACTIVE)\n pos_type POSType\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n complex_id String\n complex Complex @relation(fields: [complex_id], references: [id])\n\n device_id String?\n device Device? @relation(fields: [device_id], references: [id])\n\n provider_id String?\n provider Provider? @relation(fields: [provider_id], references: [id])\n\n account_id String @unique\n account ConsumerAccount @relation(fields: [account_id], references: [id])\n\n permission_pos PermissionPos[]\n sales_invoices SalesInvoice[]\n\n @@map(\"poses\")\n}\n\nmodel Good {\n id String @id @default(ulid())\n name String @db.VarChar(255)\n is_default_guild_good Boolean @default(false)\n pricing_model GoodPricingModel\n description String? @db.Text\n local_sku String? @unique() @db.VarChar(100)\n barcode String? @unique() @db.VarChar(100)\n base_sale_price Decimal? @default(0.00) @db.Decimal(15, 0)\n image_url String? @db.VarChar(255)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n\n sku_id String\n sku StockKeepingUnits @relation(fields: [sku_id], references: [id])\n\n measure_unit_id String\n measure_unit MeasureUnits @relation(fields: [measure_unit_id], references: [id])\n\n category_id String?\n category GoodCategory? @relation(fields: [category_id], references: [id])\n\n business_activity_id String?\n business_activity BusinessActivity? @relation(fields: [business_activity_id], references: [id])\n\n sales_invoice_items SalesInvoiceItem[]\n\n @@index([category_id])\n @@map(\"goods\")\n}\n\nmodel GoodCategory {\n id String @id @default(ulid())\n name String @db.VarChar(100)\n description String? @db.Text\n image_url String? @db.VarChar(255)\n complex_id String?\n is_default_guild_good Boolean @default(false)\n guild_id String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n\n goods Good[]\n guild Guild? @relation(fields: [guild_id], references: [id])\n complex Complex? @relation(fields: [complex_id], references: [id])\n\n @@map(\"good_categories\")\n}\n\nmodel MeasureUnits {\n id String @id @default(ulid())\n code String @unique\n name String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)\n\n goods Good[]\n\n @@map(\"measure_units\")\n}\n\nmodel StockKeepingUnits {\n id String @id @default(ulid())\n code String @unique\n name String\n VAT Decimal @db.Decimal(5, 2)\n type SKUGuildType\n is_public Boolean @default(true)\n is_domestic Boolean @default(false)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n goods Good[]\n\n @@index([code])\n @@map(\"stock_keeping_units\")\n}\n\nmodel TriggerLog {\n id Int @id @default(autoincrement())\n message String @db.Text\n createdAt DateTime @default(now()) @db.Timestamp(0)\n name String @db.Text\n\n @@map(\"trigger_logs\")\n}\n\n// generator client {\n// provider = \"prisma-client-js\"\n// // output = \"../../src/generated/prisma\"\n// // moduleFormat = \"cjs\"\n// previewFeatures = [\"views\"]\n// }\n\n// datasource db {\n// provider = \"mysql\"\n// }\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../../src/generated/prisma\"\n moduleFormat = \"cjs\"\n previewFeatures = [\"views\"]\n}\n\ndatasource db {\n provider = \"mysql\"\n}\n\nmodel Customer {\n id String @id @default(ulid())\n is_favorite Boolean? @default(false)\n type CustomerType\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n\n individual CustomerIndividual?\n legal CustomerLegal?\n\n sales_invoices SalesInvoice[]\n\n @@map(\"customers\")\n}\n\nmodel CustomerIndividual {\n first_name String @db.VarChar(255)\n last_name String @db.VarChar(255)\n national_id String @db.Char(10)\n mobile_number String @db.Char(15)\n\n postal_code String @db.Char(10)\n economic_code String? @db.Char(10)\n\n customer_id String @id\n customer Customer @relation(fields: [customer_id], references: [id], onDelete: Cascade)\n\n business_activity_id String\n business_activity BusinessActivity @relation(fields: [business_activity_id], references: id)\n\n @@unique([business_activity_id, national_id])\n @@index([business_activity_id])\n @@map(\"customer_individuals\")\n}\n\nmodel CustomerLegal {\n name String @db.VarChar(255)\n economic_code String @db.Char(10)\n registration_number String? @db.Char(20)\n postal_code String @db.Char(10)\n\n customer_id String @id\n customer Customer @relation(fields: [customer_id], references: [id], onDelete: Cascade)\n\n business_activity_id String\n business_activity BusinessActivity @relation(fields: [business_activity_id], references: id)\n\n @@unique([business_activity_id, economic_code])\n @@index([business_activity_id])\n @@map(\"customer_legal\")\n}\n\nenum PaymentMethodType {\n CHEQUE\n SET_OFF\n CASH\n TERMINAL\n PAYMENT_GATEWAY\n CARD\n BANK\n OTHER\n}\n\nenum UnitType {\n COUNT\n GRAM\n KILOGRAM\n MILLILITER\n LITER\n METER\n HOUR\n}\n\nenum GoodPricingModel {\n STANDARD\n GOLD\n}\n\nenum CustomerType {\n INDIVIDUAL\n LEGAL\n UNKNOWN\n}\n\nenum POSStatus {\n ACTIVE\n DISABLED\n}\n\nenum POSRole {\n MANAGER\n OPERATOR\n}\n\nenum ComplexRole {\n MANAGER\n OPERATOR\n}\n\nenum BusinessRole {\n MANAGER\n OPERATOR\n}\n\nenum LicenseType {\n BASIC\n PRO\n ENTERPRISE\n}\n\nenum LicenseStatus {\n ACTIVE\n EXPIRED\n SUSPENDED\n}\n\nenum POSType {\n PSP\n MOBILE\n WEB\n API\n}\n\nenum UserType {\n LEGAL\n INDIVIDUAL\n}\n\nenum AccountType {\n ADMIN\n PROVIDER\n PARTNER\n CONSUMER\n}\n\nenum UserStatus {\n ACTIVE\n INACTIVE\n}\n\nenum AccountRole {\n OWNER\n OPERATOR\n ACCOUNTANT\n}\n\nenum AccountStatus {\n ACTIVE\n SUSPENDED\n}\n\nenum PartnerRole {\n OWNER\n MANAGER\n OPERATOR\n}\n\nenum PartnerStatus {\n ACTIVE\n SUSPENDED\n}\n\nenum ProviderRole {\n OWNER\n MANAGER\n OPERATOR\n}\n\nenum ProviderStatus {\n ACTIVE\n SUSPENDED\n}\n\nenum ConsumerRole {\n OWNER\n MANAGER\n OPERATOR\n}\n\nenum ConsumerStatus {\n ACTIVE\n SUSPENDED\n}\n\nenum TokenType {\n ACCESS\n REFRESH\n}\n\nenum ApplicationPlatform {\n ANDROID\n IOS\n}\n\nenum ApplicationReleaseType {\n STABLE\n BETA\n ALPHA\n}\n\nenum ApplicationPublisher {\n DIRECT\n CAFE_BAZAR\n MAYKET\n}\n\nenum ConsumerType {\n INDIVIDUAL\n LEGAL\n}\n\nenum TspProviderType {\n NAMA\n SUN\n}\n\nenum TspProviderResponseStatus {\n SUCCESS\n FAILURE\n NOT_SEND\n QUEUED\n}\n\nenum TspProviderRequestType {\n MAIN\n UPDATE\n REVOKE\n REMOVE\n}\n\nenum TspProviderCustomerType {\n Unknown\n Known\n}\n\nenum SKUGuildType {\n GOLD\n}\n\nenum InvoiceTemplateType {\n SALE\n FX_SALE\n GOLD_JEWELRY\n CONTRACT\n UTILITY\n AIR_TICKET\n EXPORT\n BILL_OF_LADING\n PETROCHEMICAL\n COMMODITY_EXCHANGE\n INSURANCE\n}\n\nmodel Guild {\n id String @id @default(ulid())\n name String\n invoice_template InvoiceTemplateType\n code String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n business_activities BusinessActivity[]\n good_categories GoodCategory[]\n\n @@map(\"guilds\")\n}\n\nmodel SalesInvoice {\n id String @id @default(uuid())\n code String @unique @db.VarChar(100)\n total_amount Decimal @db.Decimal(15, 2)\n invoice_number Int @db.Int()\n invoice_date DateTime @default(now()) @db.Timestamp(0)\n\n notes String? @db.Text\n unknown_customer Json? @db.Json\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n\n customer_id String?\n customer Customer? @relation(fields: [customer_id], references: [id])\n\n consumer_account_id String\n consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id])\n\n pos_id String\n pos Pos @relation(fields: [pos_id], references: [id])\n\n items SalesInvoiceItem[]\n payments SalesInvoicePayment[]\n tsp_attempts SaleInvoiceTspAttempts[]\n\n @@unique([invoice_number, pos_id])\n @@map(\"sales_invoices\")\n}\n\nmodel SalesInvoiceItem {\n id String @id @default(ulid())\n quantity Decimal @db.Decimal(10, 0)\n measure_unit_text String @db.VarChar(50)\n measure_unit_code String @db.VarChar(50)\n sku_code String @db.VarChar(50)\n sku_vat Decimal @default(0.00) @db.Decimal(15, 2)\n unit_price Decimal @default(0.00) @db.Decimal(15, 2)\n total_amount Decimal @default(0.00) @db.Decimal(15, 2)\n created_at DateTime @default(now()) @db.Timestamp(0)\n discount Decimal @default(0.00) @db.Decimal(15, 2)\n notes String? @db.Text\n\n payload Json?\n good_snapshot Json\n\n invoice_id String\n invoice SalesInvoice @relation(fields: [invoice_id], references: [id])\n\n good_id String\n good Good @relation(fields: [good_id], references: [id])\n\n service_id String?\n service Service? @relation(fields: [service_id], references: [id])\n\n @@index([invoice_id, good_id])\n @@map(\"sales_invoice_items\")\n}\n\nmodel SaleInvoiceTspAttempts {\n id String @id @default(ulid())\n\n attempt_no Int\n status TspProviderResponseStatus\n tax_id String? @unique @db.VarChar(191)\n type TspProviderRequestType\n\n request_payload Json?\n response_payload Json?\n error_message String? @db.Text\n\n sent_at DateTime? @db.Timestamp(0)\n received_at DateTime? @db.Timestamp(0)\n created_at DateTime @default(now()) @db.Timestamp(0)\n\n invoice_id String @unique\n invoice SalesInvoice @relation(fields: [invoice_id], references: [id], onDelete: Cascade)\n\n @@unique([invoice_id, attempt_no])\n @@index([status])\n @@index([tax_id])\n @@index([invoice_id])\n @@map(\"sale_invoice_tsp_attempts\")\n}\n\nmodel SalesInvoicePayment {\n id String @id @default(ulid())\n amount Decimal @db.Decimal(15, 2)\n payment_method PaymentMethodType\n paid_at DateTime @db.Timestamp(0)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n\n invoice_id String\n invoice SalesInvoice @relation(fields: [invoice_id], references: [id])\n\n terminal_info SalesInvoicePaymentTerminalInfo?\n\n @@index([invoice_id])\n @@map(\"sales_invoice_payments\")\n}\n\nmodel SalesInvoicePaymentTerminalInfo {\n id String @id @default(ulid())\n terminal_id String\n stan String\n rrn String\n transaction_date_time DateTime\n customer_card_no String?\n description String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n\n payment_id String @unique\n payment SalesInvoicePayment @relation(fields: [payment_id], references: [id])\n\n @@unique([terminal_id, stan, rrn, payment_id])\n @@map(\"sales_invoice_payment_terminal_info\")\n}\n\nmodel Service {\n id String @id @default(ulid())\n name String @db.VarChar(255)\n description String? @db.Text\n sku String @unique() @db.VarChar(100)\n local_sku String? @unique() @db.VarChar(100)\n barcode String? @unique() @db.VarChar(100)\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n category_id String?\n base_sale_price Decimal @default(0.00) @db.Decimal(15, 0)\n account_id String\n complex_id String\n\n category ServiceCategory? @relation(fields: [category_id], references: [id])\n sales_invoice_items SalesInvoiceItem[]\n\n @@index([category_id])\n @@map(\"services\")\n}\n\nmodel ServiceCategory {\n id String @id @default(ulid())\n name String @db.VarChar(100)\n description String? @db.Text\n image_url String? @db.VarChar(255)\n account_id String\n complex_id String\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n\n services Service[]\n\n @@map(\"service_categories\")\n}\n", + "inlineSchema": "model AdminAccount {\n id String @id @default(ulid())\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n admin_id String\n admin Admin @relation(fields: [admin_id], references: [id])\n\n account_id String @unique\n account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)\n\n @@map(\"admin_accounts\")\n}\n\nmodel Admin {\n id String @id @default(ulid())\n mobile_number String @unique()\n national_code String? @unique()\n first_name String\n last_name String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n accounts AdminAccount[]\n\n @@map(\"admins\")\n}\n\n// model LegalProfile {\n// user_id String @id\n// company_name String\n// register_no String @unique()\n// representative_name String?\n// representative_national_id String?\n\n// // user User @relation(fields: [user_id], references: [id])\n\n// @@map(\"legal_profiles\")\n// }\n\n// model IndividualProfile {\n// user_id String @id\n// national_code String @unique()\n// first_name String\n// last_name String\n// birth_date DateTime?\n// mobile_number String\n// // user User @relation(fields: [user_id], references: [id])\n\n// @@map(\"individual_profiles\")\n// }\n\nmodel Account {\n id String @id @default(ulid())\n username String @unique()\n password String\n status AccountStatus\n type AccountType\n\n admin_account AdminAccount?\n provider_account ProviderAccount?\n partner_account PartnerAccount?\n consumer_account ConsumerAccount?\n\n // admin_account_id String? @unique\n // admin_account AdminAccount? @relation(fields: [admin_account_id], references: [id], onDelete: Cascade)\n\n // provider_account_id String? @unique\n // provider_account ProviderAccount? @relation(fields: [provider_account_id], references: [id], onDelete: Cascade)\n\n // partner_account_id String? @unique\n // partner_account PartnerAccount? @relation(fields: [partner_account_id], references: [id], onDelete: Cascade)\n\n // consumer_account_id String? @unique\n // consumer_account ConsumerAccount? @relation(fields: [consumer_account_id], references: [id], onDelete: Cascade)\n\n // tokens Token[]\n // refresh_tokens RefreshToken[]\n\n @@map(\"accounts\")\n}\n\n// model Token {\n// id String @id @d @uniqueefault(ulid())\n// token String @unique\n// type TokenType\n// created_at DateTime @default(now())\n// expires_at DateTime\n\n// account_id String\n// account Account @relation(fields: [account_id], references: [id])\n\n// @@unique([type, account_id])\n// @@map(\"tokens\")\n// }\n\n// model VerificationCode {\n// id String @id @default(ulid())\n// code String\n// is_used Boolean @default(false)\n// created_at DateTime @default(now())\n// expires_at DateTime\n\n// account_id String\n// account Account @relation(fields: [account_id], references: [id])\n\n// @@map(\"verification_codes\")\n// }\n\nmodel DeviceBrand {\n id String @id @default(ulid())\n name String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n devices Device[]\n\n @@map(\"device_brands\")\n}\n\nmodel Device {\n id String @id @default(ulid())\n name String\n os_version String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n brand_id String\n\n brand DeviceBrand @relation(fields: [brand_id], references: [id])\n poses Pos[]\n\n @@map(\"devices\")\n}\n\nmodel LicenseChargeTransaction {\n id String @id @default(ulid())\n activation_expires_at DateTime\n tracking_code String @unique()\n purchased_count Int\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n licenses License[]\n\n @@map(\"license_charged_transactions\")\n}\n\nmodel License {\n id String @id @default(ulid())\n accounts_limit Int @default(2)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n charge_transaction_id String\n charge_transaction LicenseChargeTransaction @relation(fields: [charge_transaction_id], references: [id])\n\n activation LicenseActivation?\n\n @@map(\"licenses\")\n}\n\nmodel LicenseActivation {\n id String @id @unique() @default(ulid())\n starts_at DateTime\n expires_at DateTime\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n license_id String @unique\n license License @relation(fields: [license_id], references: [id])\n\n business_activity_id String @unique\n business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])\n\n license_renews LicenseRenew[]\n account_allocations LicenseAccountAllocation[]\n\n @@map(\"licenses_activated\")\n}\n\nmodel LicenseRenewChargeTransaction {\n id String @id @default(ulid())\n activation_expires_at DateTime\n tracking_code String @unique()\n purchased_count Int\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n license_renews LicenseRenew[]\n\n @@map(\"license_renew_charge_transaction\")\n}\n\nmodel LicenseRenew {\n id String @id @default(ulid())\n expires_at DateTime\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n charge_transaction_id String\n charge_transaction LicenseRenewChargeTransaction @relation(fields: [charge_transaction_id], references: [id])\n\n activation_id String?\n activation LicenseActivation? @relation(fields: [activation_id], references: [id])\n\n @@map(\"license_renew\")\n}\n\nmodel PartnerAccountQuotaChargeTransaction {\n id String @id @default(ulid())\n activation_expires_at DateTime\n tracking_code String @unique()\n purchased_count Int\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n credits PartnerAccountQuotaCredit[]\n\n @@map(\"partner_account_quota_charge_transaction\")\n}\n\nmodel PartnerAccountQuotaCredit {\n id String @id @default(ulid())\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n charge_transaction_id String?\n charge_transaction PartnerAccountQuotaChargeTransaction? @relation(fields: [charge_transaction_id], references: [id])\n\n allocation LicenseAccountAllocation?\n\n @@map(\"partner_account_quota_credit\")\n}\n\nmodel LicenseAccountAllocation {\n id String @id @default(ulid())\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n license_activation_id String?\n license_activation LicenseActivation? @relation(fields: [license_activation_id], references: [id])\n\n account_id String? @unique\n account ConsumerAccount? @relation(fields: [account_id], references: [id])\n\n credit_id String? @unique\n credit PartnerAccountQuotaCredit? @relation(fields: [credit_id], references: [id])\n\n @@map(\"license_account_allocation\")\n}\n\nmodel PartnerAccount {\n id String @id @default(ulid())\n role PartnerRole\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n account_id String @unique\n account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)\n\n @@map(\"partner_accounts\")\n}\n\nmodel Partner {\n id String @id @default(ulid())\n name String\n code String @unique()\n status PartnerStatus @default(ACTIVE)\n tsp_provider TspProviderType @default(NAMA)\n logo_url String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)\n\n accounts PartnerAccount[]\n consumers_individual ConsumerIndividual[]\n consumers_legal ConsumerLegal[]\n license_charge_transactions LicenseChargeTransaction[]\n account_quota_charge_transactions PartnerAccountQuotaChargeTransaction[]\n license_renew_charge_transactions LicenseRenewChargeTransaction[]\n\n @@map(\"partners\")\n}\n\nmodel PermissionConsumer {\n id String @id @default(ulid())\n\n consumer_account_id String @unique\n consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id], onDelete: Cascade)\n\n pos_permissions PermissionPos[]\n complex_permissions PermissionComplex[]\n business_permissions PermissionBusiness[]\n\n @@map(\"permission_consumers\")\n}\n\nmodel PermissionPos {\n id String @id @default(ulid())\n role POSRole\n\n pos_id String\n permission_id String\n\n pos Pos @relation(fields: [pos_id], references: [id], onDelete: Cascade)\n permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)\n\n @@unique([permission_id, pos_id])\n @@map(\"permission_poses\")\n}\n\nmodel PermissionComplex {\n id String @id @default(ulid())\n role ComplexRole\n\n complex_id String\n permission_id String\n\n complex Complex @relation(fields: [complex_id], references: [id], onDelete: Cascade)\n permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)\n\n @@unique([permission_id, complex_id])\n @@map(\"permission_complexes\")\n}\n\nmodel PermissionBusiness {\n id String @id @default(ulid())\n role BusinessRole\n\n business_id String\n permission_id String\n\n business BusinessActivity @relation(fields: [business_id], references: [id], onDelete: Cascade)\n permission PermissionConsumer @relation(fields: [permission_id], references: [id], onDelete: Cascade)\n\n @@unique([permission_id, business_id])\n @@map(\"permission_business_activities\")\n}\n\nmodel ProviderAccount {\n id String @id @default(ulid())\n role ProviderRole\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n provider_id String\n provider Provider @relation(fields: [provider_id], references: [id])\n\n account_id String @unique\n account Account @relation(fields: [account_id], references: [id], onDelete: Cascade)\n\n @@map(\"provider_accounts\")\n}\n\nmodel Provider {\n id String @id @default(ulid())\n code String @unique()\n status PartnerStatus @default(ACTIVE)\n name String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n\n accounts ProviderAccount[]\n pos_list Pos[]\n\n @@map(\"providers\")\n}\n\nmodel ConsumerDevices {\n uuid String @id @unique() @db.VarChar(255)\n app_version String @db.VarChar(20)\n build_number String @db.VarChar(20)\n platform String @db.VarChar(100)\n brand String @db.VarChar(100)\n model String @db.VarChar(100)\n device String @db.VarChar(100)\n publisher ApplicationPublisher\n os_version String @db.VarChar(20)\n sdk_version String @db.VarChar(20)\n release_number String @db.VarChar(20)\n user_agent String? @db.VarChar(100)\n browser_name String? @db.VarChar(100)\n fcm_token String? @db.VarChar(100)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n consumer_id String\n consumer Consumer @relation(fields: [consumer_id], references: [id])\n\n @@map(\"consumer_devices\")\n}\n\nmodel ApplicationReleasedInfo {\n id String @id @default(ulid())\n version String\n build_number String\n is_minimum_supported Boolean @default(false)\n release_type ApplicationReleaseType\n platform ApplicationPlatform\n notes Json?\n\n release_date DateTime @default(now()) @db.Timestamp(0)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n @@map(\"application_released_info\")\n}\n\nmodel ConsumerAccount {\n id String @id @default(ulid())\n role ConsumerRole\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n consumer_id String\n consumer Consumer @relation(fields: [consumer_id], references: [id])\n\n account_id String @unique()\n account Account @relation(fields: [account_id], references: [id])\n\n pos Pos?\n permission PermissionConsumer?\n account_allocation LicenseAccountAllocation?\n sales_invoices SalesInvoice[]\n\n @@map(\"consumer_accounts\")\n}\n\nmodel Consumer {\n id String @id @default(ulid())\n type ConsumerType\n status ConsumerStatus @default(ACTIVE)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n accounts ConsumerAccount[]\n business_activities BusinessActivity[]\n devices ConsumerDevices[]\n individual ConsumerIndividual?\n legal ConsumerLegal?\n\n @@map(\"consumers\")\n}\n\nmodel ConsumerIndividual {\n first_name String\n last_name String\n mobile_number String\n national_code String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n consumer_id String @id\n consumer Consumer @relation(fields: [consumer_id], references: [id], onDelete: Cascade)\n\n @@unique([mobile_number, consumer_id])\n @@unique([partner_id, national_code])\n @@map(\"consumers_individual\")\n}\n\nmodel ConsumerLegal {\n name String\n registration_code String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n partner_id String\n partner Partner @relation(fields: [partner_id], references: [id])\n\n consumer_id String @id\n consumer Consumer @relation(fields: [consumer_id], references: [id], onDelete: Cascade)\n\n @@unique([partner_id, registration_code])\n @@map(\"consumers_legal\")\n}\n\nmodel BusinessActivity {\n id String @id @default(ulid())\n economic_code String\n name String\n fiscal_id String\n partner_token String\n invoice_number_sequence Decimal @default(1) @db.Decimal(20, 0)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n guild_id String\n guild Guild @relation(fields: [guild_id], references: [id])\n\n consumer_id String\n consumer Consumer @relation(fields: [consumer_id], references: [id])\n\n license_activation LicenseActivation?\n complexes Complex[]\n permission_businesses PermissionBusiness[]\n goods Good[]\n customer_individuals CustomerIndividual[]\n customer_legals CustomerLegal[]\n\n @@unique([economic_code, consumer_id])\n @@map(\"business_activities\")\n}\n\nmodel Complex {\n id String @id @default(ulid())\n name String\n branch_code String\n address String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n business_activity_id String\n\n business_activity BusinessActivity @relation(fields: [business_activity_id], references: [id])\n\n pos_list Pos[]\n good_categories GoodCategory[]\n permission_complexes PermissionComplex[]\n\n @@map(\"complexes\")\n}\n\nmodel Pos {\n id String @id @default(ulid())\n name String\n model String?\n serial_number String? @unique()\n status POSStatus @default(ACTIVE)\n pos_type POSType\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n complex_id String\n complex Complex @relation(fields: [complex_id], references: [id])\n\n device_id String?\n device Device? @relation(fields: [device_id], references: [id])\n\n provider_id String?\n provider Provider? @relation(fields: [provider_id], references: [id])\n\n account_id String @unique\n account ConsumerAccount @relation(fields: [account_id], references: [id])\n\n permission_pos PermissionPos[]\n sales_invoices SalesInvoice[]\n\n @@map(\"poses\")\n}\n\nmodel Good {\n id String @id @default(ulid())\n name String @db.VarChar(255)\n is_default_guild_good Boolean @default(false)\n pricing_model GoodPricingModel\n description String? @db.Text\n local_sku String? @unique() @db.VarChar(100)\n barcode String? @unique() @db.VarChar(100)\n base_sale_price Decimal? @default(0.00) @db.Decimal(15, 0)\n image_url String? @db.VarChar(255)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n\n sku_id String\n sku StockKeepingUnits @relation(fields: [sku_id], references: [id])\n\n measure_unit_id String\n measure_unit MeasureUnits @relation(fields: [measure_unit_id], references: [id])\n\n category_id String?\n category GoodCategory? @relation(fields: [category_id], references: [id])\n\n business_activity_id String?\n business_activity BusinessActivity? @relation(fields: [business_activity_id], references: [id])\n\n sales_invoice_items SalesInvoiceItem[]\n\n @@index([category_id])\n @@map(\"goods\")\n}\n\nmodel GoodCategory {\n id String @id @default(ulid())\n name String @db.VarChar(100)\n description String? @db.Text\n image_url String? @db.VarChar(255)\n complex_id String?\n is_default_guild_good Boolean @default(false)\n guild_id String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n\n goods Good[]\n guild Guild? @relation(fields: [guild_id], references: [id])\n complex Complex? @relation(fields: [complex_id], references: [id])\n\n @@map(\"good_categories\")\n}\n\nmodel MeasureUnits {\n id String @id @default(ulid())\n code String @unique\n name String\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @default(now()) @updatedAt @db.Timestamp(0)\n\n goods Good[]\n\n @@map(\"measure_units\")\n}\n\nmodel StockKeepingUnits {\n id String @id @default(ulid())\n code String @unique\n name String\n VAT Decimal @db.Decimal(5, 2)\n type SKUGuildType\n is_public Boolean @default(true)\n is_domestic Boolean @default(false)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n goods Good[]\n\n @@index([code])\n @@map(\"stock_keeping_units\")\n}\n\nmodel TriggerLog {\n id Int @id @default(autoincrement())\n message String @db.Text\n createdAt DateTime @default(now()) @db.Timestamp(0)\n name String @db.Text\n\n @@map(\"trigger_logs\")\n}\n\n// generator client {\n// provider = \"prisma-client-js\"\n// // output = \"../../src/generated/prisma\"\n// // moduleFormat = \"cjs\"\n// previewFeatures = [\"views\"]\n// }\n\n// datasource db {\n// provider = \"mysql\"\n// }\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../../src/generated/prisma\"\n moduleFormat = \"cjs\"\n previewFeatures = [\"views\"]\n}\n\ndatasource db {\n provider = \"mysql\"\n}\n\nmodel Customer {\n id String @id @default(ulid())\n is_favorite Boolean? @default(false)\n type CustomerType\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n\n individual CustomerIndividual?\n legal CustomerLegal?\n\n sales_invoices SalesInvoice[]\n\n @@map(\"customers\")\n}\n\nmodel CustomerIndividual {\n first_name String @db.VarChar(255)\n last_name String @db.VarChar(255)\n national_id String @db.Char(10)\n mobile_number String @db.Char(15)\n\n postal_code String @db.Char(10)\n economic_code String? @db.Char(10)\n\n customer_id String @id\n customer Customer @relation(fields: [customer_id], references: [id], onDelete: Cascade)\n\n business_activity_id String\n business_activity BusinessActivity @relation(fields: [business_activity_id], references: id)\n\n @@unique([business_activity_id, national_id])\n @@index([business_activity_id])\n @@map(\"customer_individuals\")\n}\n\nmodel CustomerLegal {\n name String @db.VarChar(255)\n economic_code String @db.Char(10)\n registration_number String? @db.Char(20)\n postal_code String @db.Char(10)\n\n customer_id String @id\n customer Customer @relation(fields: [customer_id], references: [id], onDelete: Cascade)\n\n business_activity_id String\n business_activity BusinessActivity @relation(fields: [business_activity_id], references: id)\n\n @@unique([business_activity_id, economic_code])\n @@index([business_activity_id])\n @@map(\"customer_legal\")\n}\n\nenum PaymentMethodType {\n CHEQUE\n SET_OFF\n CASH\n TERMINAL\n PAYMENT_GATEWAY\n CARD\n BANK\n OTHER\n}\n\nenum UnitType {\n COUNT\n GRAM\n KILOGRAM\n MILLILITER\n LITER\n METER\n HOUR\n}\n\nenum GoodPricingModel {\n STANDARD\n GOLD\n}\n\nenum CustomerType {\n INDIVIDUAL\n LEGAL\n UNKNOWN\n}\n\nenum POSStatus {\n ACTIVE\n DISABLED\n}\n\nenum POSRole {\n MANAGER\n OPERATOR\n}\n\nenum ComplexRole {\n MANAGER\n OPERATOR\n}\n\nenum BusinessRole {\n MANAGER\n OPERATOR\n}\n\nenum LicenseType {\n BASIC\n PRO\n ENTERPRISE\n}\n\nenum LicenseStatus {\n ACTIVE\n EXPIRED\n SUSPENDED\n}\n\nenum POSType {\n PSP\n MOBILE\n WEB\n API\n}\n\nenum UserType {\n LEGAL\n INDIVIDUAL\n}\n\nenum AccountType {\n ADMIN\n PROVIDER\n PARTNER\n CONSUMER\n}\n\nenum UserStatus {\n ACTIVE\n INACTIVE\n}\n\nenum AccountRole {\n OWNER\n OPERATOR\n ACCOUNTANT\n}\n\nenum AccountStatus {\n ACTIVE\n SUSPENDED\n}\n\nenum PartnerRole {\n OWNER\n MANAGER\n OPERATOR\n}\n\nenum PartnerStatus {\n ACTIVE\n SUSPENDED\n}\n\nenum ProviderRole {\n OWNER\n MANAGER\n OPERATOR\n}\n\nenum ProviderStatus {\n ACTIVE\n SUSPENDED\n}\n\nenum ConsumerRole {\n OWNER\n MANAGER\n OPERATOR\n}\n\nenum ConsumerStatus {\n ACTIVE\n SUSPENDED\n}\n\nenum TokenType {\n ACCESS\n REFRESH\n}\n\nenum ApplicationPlatform {\n ANDROID\n IOS\n}\n\nenum ApplicationReleaseType {\n STABLE\n BETA\n ALPHA\n}\n\nenum ApplicationPublisher {\n DIRECT\n CAFE_BAZAR\n MAYKET\n}\n\nenum ConsumerType {\n INDIVIDUAL\n LEGAL\n}\n\nenum TspProviderType {\n NAMA\n SUN\n}\n\nenum TspProviderResponseStatus {\n SUCCESS\n FAILURE\n NOT_SEND\n QUEUED\n REVOKED\n}\n\nenum TspProviderRequestType {\n MAIN\n UPDATE\n REVOKE\n RETURN\n}\n\nenum TspProviderCustomerType {\n Unknown\n Known\n}\n\nenum SKUGuildType {\n GOLD\n}\n\nenum InvoiceTemplateType {\n SALE\n FX_SALE\n GOLD_JEWELRY\n CONTRACT\n UTILITY\n AIR_TICKET\n EXPORT\n BILL_OF_LADING\n PETROCHEMICAL\n COMMODITY_EXCHANGE\n INSURANCE\n}\n\nmodel Guild {\n id String @id @default(ulid())\n name String\n invoice_template InvoiceTemplateType\n code String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt() @db.Timestamp(0)\n\n business_activities BusinessActivity[]\n good_categories GoodCategory[]\n\n @@map(\"guilds\")\n}\n\nmodel SalesInvoice {\n id String @id @default(uuid())\n code String @unique @db.VarChar(100)\n total_amount Decimal @db.Decimal(15, 2)\n invoice_number Int @db.Int()\n invoice_date DateTime @default(now()) @db.Timestamp(0)\n\n notes String? @db.Text\n unknown_customer Json? @db.Json\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n\n customer_id String?\n customer Customer? @relation(fields: [customer_id], references: [id])\n\n consumer_account_id String\n consumer_account ConsumerAccount @relation(fields: [consumer_account_id], references: [id])\n\n pos_id String\n pos Pos @relation(fields: [pos_id], references: [id])\n\n items SalesInvoiceItem[]\n payments SalesInvoicePayment[]\n tsp_attempts SaleInvoiceTspAttempts[]\n\n @@unique([invoice_number, pos_id])\n @@map(\"sales_invoices\")\n}\n\nmodel SalesInvoiceItem {\n id String @id @default(ulid())\n quantity Decimal @db.Decimal(10, 0)\n measure_unit_text String @db.VarChar(50)\n measure_unit_code String @db.VarChar(50)\n sku_code String @db.VarChar(50)\n sku_vat Decimal @default(0.00) @db.Decimal(15, 2)\n unit_price Decimal @default(0.00) @db.Decimal(15, 2)\n total_amount Decimal @default(0.00) @db.Decimal(15, 2)\n created_at DateTime @default(now()) @db.Timestamp(0)\n discount Decimal @default(0.00) @db.Decimal(15, 2)\n notes String? @db.Text\n\n payload Json?\n good_snapshot Json\n\n invoice_id String\n invoice SalesInvoice @relation(fields: [invoice_id], references: [id])\n\n good_id String\n good Good @relation(fields: [good_id], references: [id])\n\n service_id String?\n service Service? @relation(fields: [service_id], references: [id])\n\n @@index([invoice_id, good_id])\n @@map(\"sales_invoice_items\")\n}\n\nmodel SaleInvoiceTspAttempts {\n id String @id @default(ulid())\n\n attempt_no Int\n status TspProviderResponseStatus\n tax_id String? @unique @db.VarChar(191)\n type TspProviderRequestType\n\n request_payload Json?\n response_payload Json?\n error_message String? @db.Text\n\n sent_at DateTime? @db.Timestamp(0)\n received_at DateTime? @db.Timestamp(0)\n created_at DateTime @default(now()) @db.Timestamp(0)\n\n invoice_id String @unique\n invoice SalesInvoice @relation(fields: [invoice_id], references: [id], onDelete: Cascade)\n\n @@unique([invoice_id, attempt_no])\n @@index([status])\n @@index([tax_id])\n @@index([invoice_id])\n @@map(\"sale_invoice_tsp_attempts\")\n}\n\nmodel SalesInvoicePayment {\n id String @id @default(ulid())\n amount Decimal @db.Decimal(15, 2)\n payment_method PaymentMethodType\n paid_at DateTime @db.Timestamp(0)\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n\n invoice_id String\n invoice SalesInvoice @relation(fields: [invoice_id], references: [id])\n\n terminal_info SalesInvoicePaymentTerminalInfo?\n\n @@index([invoice_id])\n @@map(\"sales_invoice_payments\")\n}\n\nmodel SalesInvoicePaymentTerminalInfo {\n id String @id @default(ulid())\n terminal_id String\n stan String\n rrn String\n transaction_date_time DateTime\n customer_card_no String?\n description String?\n\n created_at DateTime @default(now()) @db.Timestamp(0)\n\n payment_id String @unique\n payment SalesInvoicePayment @relation(fields: [payment_id], references: [id])\n\n @@unique([terminal_id, stan, rrn, payment_id])\n @@map(\"sales_invoice_payment_terminal_info\")\n}\n\nmodel Service {\n id String @id @default(ulid())\n name String @db.VarChar(255)\n description String? @db.Text\n sku String @unique() @db.VarChar(100)\n local_sku String? @unique() @db.VarChar(100)\n barcode String? @unique() @db.VarChar(100)\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n category_id String?\n base_sale_price Decimal @default(0.00) @db.Decimal(15, 0)\n account_id String\n complex_id String\n\n category ServiceCategory? @relation(fields: [category_id], references: [id])\n sales_invoice_items SalesInvoiceItem[]\n\n @@index([category_id])\n @@map(\"services\")\n}\n\nmodel ServiceCategory {\n id String @id @default(ulid())\n name String @db.VarChar(100)\n description String? @db.Text\n image_url String? @db.VarChar(255)\n account_id String\n complex_id String\n created_at DateTime @default(now()) @db.Timestamp(0)\n updated_at DateTime @updatedAt @db.Timestamp(0)\n deleted_at DateTime? @db.Timestamp(0)\n\n services Service[]\n\n @@map(\"service_categories\")\n}\n", "runtimeDataModel": { "models": {}, "enums": {}, diff --git a/src/main.ts b/src/main.ts index b74b65f..84a831f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -61,6 +61,9 @@ async function bootstrap() { 'http://localhost:5000', 'http://127.0.0.1:5000', 'http://192.168.128.73:5000', + 'http://localhost:5005', + 'http://127.0.0.1:5005', + 'http://192.168.128.73:5005', ] const envOrigins = process.env.CORS_ORIGINS ? process.env.CORS_ORIGINS.split(',') diff --git a/src/modules/consumer/saleInvoices/saleInvoices.module.ts b/src/modules/consumer/saleInvoices/saleInvoices.module.ts index 93e7f19..9cc4493 100644 --- a/src/modules/consumer/saleInvoices/saleInvoices.module.ts +++ b/src/modules/consumer/saleInvoices/saleInvoices.module.ts @@ -1,22 +1,13 @@ +import { SaleInvoiceTspModule } from '@/modules/tspProviders/sales-invoice-tsp.module' import { PrismaModule } from '@/prisma/prisma.module' import { Module } from '@nestjs/common' -import { HttpClientUtil } from '../../../common/utils/http-client.util' -import { SalesInvoiceTspSwitchService } from '../../tspProviders/sales-invoice-tsp-switch.service' -import { SalesInvoiceTspService } from '../../tspProviders/sales-invoice-tsp.service' -import { NamaProviderSwitchAdapter } from '../../tspProviders/switch/nama/nama-provider.adapter' import { StatisticsController } from './saleInvoices.controller' import { SaleInvoicesService } from './saleInvoices.service' @Module({ - imports: [PrismaModule], + imports: [PrismaModule, SaleInvoiceTspModule], controllers: [StatisticsController], - providers: [ - SaleInvoicesService, - HttpClientUtil, - SalesInvoiceTspService, - SalesInvoiceTspSwitchService, - NamaProviderSwitchAdapter, - ], + providers: [SaleInvoicesService], exports: [SaleInvoicesService], }) export class ConsumerSaleInvoicesModule {} diff --git a/src/modules/partners/utils/getPartnerRemainingLicenses.util.ts b/src/modules/partners/utils/getPartnerRemainingLicenses.util.ts index 405ad6e..8e1ac69 100644 --- a/src/modules/partners/utils/getPartnerRemainingLicenses.util.ts +++ b/src/modules/partners/utils/getPartnerRemainingLicenses.util.ts @@ -66,13 +66,16 @@ export const getPartnerFirstRemainingLicense = async ( id: true, charge_transaction_id: true, accounts_limit: true, + parent: { + select: { + name: true, + }, + }, }, }) if (!license) { - throw new BadRequestException( - 'لایسنس فعال و استفاده نشده برای این شریک تجاری وجود ندارد.', - ) + throw new BadRequestException(`لایسنس فعالی برای ${license.parent.name} وجود ندارد.`) } return license @@ -85,9 +88,7 @@ export const ensurePartnerHasRemainingLicense = async ( const quota = await getPartnerRemainingLicenses(prisma, params) if (quota.remaining_count <= 0) { - throw new BadRequestException( - 'لایسنس فعال و استفاده نشده برای این شریک تجاری وجود ندارد.', - ) + throw new BadRequestException('لایسنس فعالی برای این شریک تجاری وجود ندارد.') } return quota diff --git a/src/modules/pos/sales-invoices/sales-invoices.controller.ts b/src/modules/pos/sales-invoices/sales-invoices.controller.ts index f693f2f..af24a66 100644 --- a/src/modules/pos/sales-invoices/sales-invoices.controller.ts +++ b/src/modules/pos/sales-invoices/sales-invoices.controller.ts @@ -39,6 +39,11 @@ export class SalesInvoicesController { return this.salesInvoicesService.send(id, posInfo) } + @Post(':id/revoke') + revoke(@Param('id') id: string, @PosInfo() posInfo: IPosPayload) { + return this.salesInvoicesService.revoke(id, posInfo) + } + // @Post('send/bulk') // sendBulk(@Body() data: SendBulkSalesInvoicesDto, @PosInfo() posInfo: IPosPayload) { // return this.salesInvoicesService.sendBulk(data.invoice_ids, posInfo) diff --git a/src/modules/pos/sales-invoices/sales-invoices.module.ts b/src/modules/pos/sales-invoices/sales-invoices.module.ts index e6a3086..9b4f109 100644 --- a/src/modules/pos/sales-invoices/sales-invoices.module.ts +++ b/src/modules/pos/sales-invoices/sales-invoices.module.ts @@ -1,19 +1,11 @@ +import { SaleInvoiceTspModule } from '@/modules/tspProviders/sales-invoice-tsp.module' import { Module } from '@nestjs/common' -import { HttpClientUtil } from '../../../common/utils/http-client.util' -import { SalesInvoiceTspSwitchService } from '../../tspProviders/sales-invoice-tsp-switch.service' -import { SalesInvoiceTspService } from '../../tspProviders/sales-invoice-tsp.service' -import { NamaProviderSwitchAdapter } from '../../tspProviders/switch/nama/nama-provider.adapter' import { SalesInvoicesController } from './sales-invoices.controller' import { SalesInvoicesService } from './sales-invoices.service' @Module({ + imports: [SaleInvoiceTspModule], controllers: [SalesInvoicesController], - providers: [ - SalesInvoicesService, - HttpClientUtil, - SalesInvoiceTspService, - SalesInvoiceTspSwitchService, - NamaProviderSwitchAdapter, - ], + providers: [SalesInvoicesService], }) export class PosSalesInvoicesModule {} diff --git a/src/modules/pos/sales-invoices/sales-invoices.service.ts b/src/modules/pos/sales-invoices/sales-invoices.service.ts index 8fac6af..7850427 100644 --- a/src/modules/pos/sales-invoices/sales-invoices.service.ts +++ b/src/modules/pos/sales-invoices/sales-invoices.service.ts @@ -273,6 +273,14 @@ export class SalesInvoicesService { return ResponseMapper.single(invoice) } + async revoke(invoiceId: string, posInfo: IPosPayload) { + await this.checkAccessToInvoice(posInfo.consumer_account_id, posInfo.pos_id) + + const invoice = await this.salesInvoiceTaxService.revoke(posInfo.pos_id, invoiceId) + + return ResponseMapper.single(invoice) + } + async inquiry(consumer_account_id: string, pos_id: string, invoiceId: string) { const consumer_id = await this.checkAccessToInvoice(consumer_account_id, pos_id) const invoice = await this.salesInvoiceTaxService.get(invoiceId, pos_id, consumer_id) diff --git a/src/modules/tspProviders/dto/provider-switch.dto.ts b/src/modules/tspProviders/dto/provider-switch.dto.ts index 62f171f..4223e5a 100644 --- a/src/modules/tspProviders/dto/provider-switch.dto.ts +++ b/src/modules/tspProviders/dto/provider-switch.dto.ts @@ -292,9 +292,81 @@ export class TspProviderGetResultDto { received_at: string } +export class TspProviderRevokePayloadDto { + @ApiProperty({ required: true, nullable: true }) + @IsNumber() + invoice_number: number + + @ApiProperty({ required: true, nullable: true }) + @IsString() + invoice_id: string + + @ApiProperty({ required: true, enum: TspProviderType }) + @IsEnum(TspProviderType) + tsp_provider: TspProviderType + + @ApiProperty({ required: true, nullable: true }) + @IsString() + economic_code: string + + @ApiProperty({ required: true, nullable: true }) + @IsString() + fiscal_id: string + + @ApiProperty({ required: true }) + @IsString() + tsp_token: string + + @ApiProperty({ required: true }) + @IsString() + last_attempt_tax_id: string +} + +export class TspProviderRevokeResponseDto { + @ApiProperty({ required: true, nullable: true }) + @IsString() + invoice_id: string + + @ApiProperty({ required: true }) + @IsString() + tax_id: string + + @ApiProperty({ enum: TspProviderResponseStatus }) + @IsEnum(TspProviderResponseStatus) + status: TspProviderResponseStatus + + @ApiProperty({ required: true }) + @IsBoolean() + hasError: boolean + + @ApiProperty({ required: false, nullable: true }) + @IsOptional() + @IsString() + message?: string | null + + @ApiProperty({ required: false, nullable: true, type: Object }) + @IsOptional() + @IsObject() + request_payload?: unknown + + @ApiProperty({ required: false, nullable: true, type: Object }) + @IsOptional() + @IsObject() + response_payload?: unknown + + @ApiProperty({ required: true }) + @IsDateString() + sent_at: string + + @ApiProperty({ required: true }) + @IsDateString() + received_at: string +} + export interface IProviderSwitchAdapter { readonly code: string send(payload: TspProviderSendPayloadDto): Promise sendBulk(payloads: TspProviderSendPayloadDto[]): Promise get(invoiceId: string, tsp_token: string): Promise + revoke(payload: TspProviderRevokePayloadDto): Promise } diff --git a/src/modules/tspProviders/sales-invoice-tsp-switch.service.ts b/src/modules/tspProviders/sales-invoice-tsp-switch.service.ts index 1e6fc61..b2e7c09 100644 --- a/src/modules/tspProviders/sales-invoice-tsp-switch.service.ts +++ b/src/modules/tspProviders/sales-invoice-tsp-switch.service.ts @@ -2,6 +2,8 @@ import { Injectable } from '@nestjs/common' import { TspProviderBulkSendResultDto, TspProviderGetResultDto, + TspProviderRevokePayloadDto, + TspProviderRevokeResponseDto, TspProviderSendItemResultDto, TspProviderSendPayloadDto, } from './dto/provider-switch.dto' @@ -56,4 +58,11 @@ export class SalesInvoiceTspSwitchService { const adapter = this.resolveSwitch(providerCode) return await adapter.get(invoiceId, tspToken) } + + async revoke( + payload: TspProviderRevokePayloadDto, + ): Promise { + const adapter = this.resolveSwitch(payload.tsp_provider) + return adapter.revoke(payload) + } } diff --git a/src/modules/tspProviders/sales-invoice-tsp.module.ts b/src/modules/tspProviders/sales-invoice-tsp.module.ts new file mode 100644 index 0000000..0ace44b --- /dev/null +++ b/src/modules/tspProviders/sales-invoice-tsp.module.ts @@ -0,0 +1,26 @@ +import { HttpClientUtil } from '@/common/utils' +import { NamaProviderUtils } from '@/modules/tspProviders/switch/nama/nama-provider.util' +import { PrismaModule } from '@/prisma/prisma.module' +import { Module } from '@nestjs/common' +import { SalesInvoiceTspSwitchService } from './sales-invoice-tsp-switch.service' +import { SalesInvoiceTspService } from './sales-invoice-tsp.service' +import { NamaProviderSwitchAdapter } from './switch/nama/nama-provider.adapter' + +@Module({ + imports: [PrismaModule], + providers: [ + HttpClientUtil, + SalesInvoiceTspService, + SalesInvoiceTspSwitchService, + NamaProviderSwitchAdapter, + NamaProviderUtils, + ], + exports: [ + HttpClientUtil, + SalesInvoiceTspService, + SalesInvoiceTspSwitchService, + NamaProviderSwitchAdapter, + NamaProviderUtils, + ], +}) +export class SaleInvoiceTspModule {} diff --git a/src/modules/tspProviders/sales-invoice-tsp.service.ts b/src/modules/tspProviders/sales-invoice-tsp.service.ts index 901a095..afc8aad 100644 --- a/src/modules/tspProviders/sales-invoice-tsp.service.ts +++ b/src/modules/tspProviders/sales-invoice-tsp.service.ts @@ -7,6 +7,8 @@ import { } from 'generated/prisma/client' import { CreateSalesInvoiceDto } from '../pos/sales-invoices/dto/create-sales-invoice.dto' import { + TspProviderRevokePayloadDto, + TspProviderRevokeResponseDto, TspProviderSendItemResultDto, TspProviderSendPayloadDto, } from './dto/provider-switch.dto' @@ -239,25 +241,40 @@ export class SalesInvoiceTspService { }, }) - if (!lastAttempt || lastAttempt?.status === TspProviderResponseStatus.QUEUED) { + if (!lastAttempt) { + throw new NotFoundException('صورت‌حساب ارسالی فاکتور شما به سامانه یافت نشد.') + } + + if (lastAttempt.status === TspProviderResponseStatus.QUEUED) { throw new BadRequestException( 'فاکتور هنوز به سامانه مالیاتی ارسال نشده است یا در صف ارسال قرار دارد. لطفا بعدا تلاش کنید.', ) } - let isUpdated = false - let isBackFromSale = false - for (let item of dataToUpdate.items) { - const lastAttemptInvoiceItem = lastAttempt.invoice.items.find( - prevItem => prevItem.good_id === item.good_id, - ) - if (!lastAttemptInvoiceItem) { - isBackFromSale = true - break + const countByGoodId = (goodIds: string[]): Map => { + const counts = new Map() + for (const goodId of goodIds) { + counts.set(goodId, (counts.get(goodId) ?? 0) + 1) } + return counts } - if (dataToUpdate.total_amount !== lastAttempt.invoice.total_amount.toNumber()) { - isUpdated = true + + const updatedGoodIds = dataToUpdate.items.map(item => item.good_id!) + const previousGoodIds = lastAttempt.invoice.items.map(item => item.good_id) + + const updatedCounts = countByGoodId(updatedGoodIds) + const previousCounts = countByGoodId(previousGoodIds) + + let isBackFromSale = false + if (updatedCounts.size !== previousCounts.size) { + isBackFromSale = true + } else { + for (const [goodId, count] of updatedCounts) { + if (previousCounts.get(goodId) !== count) { + isBackFromSale = true + break + } + } } const attempt = await this.prisma.saleInvoiceTspAttempts.create({ @@ -308,6 +325,62 @@ export class SalesInvoiceTspService { } } + async revoke( + pos_id: string, + invoice_id: string, + ): Promise { + const attempt = await this.prisma.saleInvoiceTspAttempts.findFirst({ + where: { + invoice_id, + }, + orderBy: { + attempt_no: 'desc', + }, + take: 1, + select: { + tax_id: true, + status: true, + attempt_no: true, + invoice: { + select: { + invoice_number: true, + }, + }, + }, + }) + + if (!attempt) { + throw new NotFoundException('صورت‌حساب ارسالی فاکتور شما به سامانه یافت نشد.') + } + if (attempt.status === TspProviderResponseStatus.QUEUED) { + throw new BadRequestException( + 'فاکتور هنوز به سامانه مالیاتی ارسال نشده است یا در صف ارسال قرار دارد. لطفا بعدا تلاش کنید.', + ) + } + + const payload = await this.buildRevokePayload(invoice_id, pos_id) + + const result = await this.tspSwitchService.revoke(payload) + + if (result) { + await this.prisma.saleInvoiceTspAttempts.create({ + data: { + attempt_no: attempt.attempt_no + 1, + invoice_id, + status: TspProviderResponseStatus.REVOKED, + type: TspProviderRequestType.REVOKE, + received_at: new Date(), + request_payload: JSON.parse(JSON.stringify(result.request_payload)), + sent_at: result.sent_at ? new Date(result.sent_at) : new Date(), + response_payload: JSON.parse(JSON.stringify(result)), + tax_id: result.tax_id, + }, + }) + } + + return result + } + private async getPosId(consumer_id: string, invoice_id: string): Promise { const now = new Date() const saleInvoice = await this.prisma.salesInvoice.findUnique({ @@ -374,6 +447,94 @@ export class SalesInvoiceTspService { return saleInvoice.pos.id } + private async buildRevokePayload( + invoiceId: string, + posId: string, + ): Promise { + const invoice = await this.prisma.salesInvoice.findUnique({ + where: { + id: invoiceId, + pos_id: posId, + }, + select: { + id: true, + code: true, + total_amount: true, + invoice_date: true, + invoice_number: true, + tsp_attempts: { + orderBy: { + created_at: 'asc', + }, + take: 1, + select: { + id: true, + status: true, + }, + }, + pos: { + select: { + complex: { + select: { + business_activity: { + select: { + fiscal_id: true, + economic_code: true, + partner_token: true, + guild: { + select: { + invoice_template: true, + }, + }, + consumer: { + select: { + legal: { + select: { + partner: { + select: { + tsp_provider: true, + }, + }, + }, + }, + individual: { + select: { + partner: { + select: { + tsp_provider: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }) + + if (!invoice) { + throw new NotFoundException('فاکتور مورد نظر یافت نشد.') + } + + const { partner } = (invoice.pos.complex.business_activity.consumer.legal || + invoice.pos.complex.business_activity.consumer.individual)! + + return { + invoice_id: invoice.id, + invoice_number: invoice.invoice_number, + economic_code: invoice.pos.complex.business_activity.economic_code, + fiscal_id: invoice.pos.complex.business_activity.fiscal_id, + tsp_token: invoice.pos.complex.business_activity.partner_token, + tsp_provider: partner.tsp_provider!, + last_attempt_tax_id: invoice.tsp_attempts[0].id, + } + } + private async buildPayload( invoiceId: string, posId: string, diff --git a/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts b/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts index 826bdad..c704bb8 100644 --- a/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts +++ b/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts @@ -4,31 +4,25 @@ import { FetchRequestInterceptor, } from '@/common/interceptors/fetch-request.interceptor' import { HttpClientUtil } from '@/common/utils/http-client.util' -import { - CustomerType, - InvoiceTemplateType, - PaymentMethodType, - TspProviderCustomerType, - TspProviderRequestType, - TspProviderResponseStatus, -} from '@/generated/prisma/enums' +import { TspProviderResponseStatus } from '@/generated/prisma/enums' import { Injectable, Logger } from '@nestjs/common' import { - CustomerInfoDto, IProviderSwitchAdapter, - PaymentInfoDto, TspProviderBulkSendResultDto, TspProviderGetResultDto, + TspProviderRevokePayloadDto, + TspProviderRevokeResponseDto, TspProviderSendItemResultDto, TspProviderSendPayloadDto, } from '../../dto/provider-switch.dto' import { NamaProviderGetResponseDto, - NamaProviderPaymentInfoDto, - NamaProviderRequestDto, NamaProviderResponseStatus, + NamaProviderRevokeRequestDto, + NamaProviderRevokeResponseDto, NamaProviderSendItemResponseDto, } from './nama-provider.dto' +import { NamaProviderUtils } from './nama-provider.util' @Injectable() export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter { @@ -43,7 +37,10 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter { private readonly sendBulkPath = '/api/v1/invoices' private readonly checkBulkStatus = '/api/v1/invoices/check-by-uuids' private readonly getPath = '/api/v1/invoices' - constructor(private readonly httpClient: HttpClientUtil) {} + constructor( + private readonly httpClient: HttpClientUtil, + private readonly namaProviderUtils: NamaProviderUtils, + ) {} private get baseUrl() { return this.sandboxBaseUrl @@ -77,7 +74,7 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter { } async send(payload: TspProviderSendPayloadDto): Promise { - const mappedRequest = this.mapToNamaRequestDto(payload) + const mappedRequest = this.namaProviderUtils.mapToNamaRequestDto(payload) try { console.log(mappedRequest) @@ -101,7 +98,7 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter { response_payload: providerResponse, received_at: providerResponse.tsp_update_time, tax_id: providerResponse.tax_id, - status: this.mapResponseStatus( + status: this.namaProviderUtils.mapResponseStatus( providerResponse.status as NamaProviderResponseStatus, ), } @@ -156,7 +153,7 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter { sent_at: new Date().toISOString(), received_at: providerResponse.tsp_update_time || new Date().toISOString(), tax_id: providerResponse.tax_id, - status: this.mapResponseStatus( + status: this.namaProviderUtils.mapResponseStatus( providerResponse.status as NamaProviderResponseStatus, ), } @@ -177,164 +174,52 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter { } } - private mapResponseStatus( - status: NamaProviderResponseStatus, - ): TspProviderResponseStatus { - switch (status.toUpperCase()) { - case NamaProviderResponseStatus.SUCCESS: - case NamaProviderResponseStatus.POSTED: - return TspProviderResponseStatus.SUCCESS - case NamaProviderResponseStatus.PENDING: - case NamaProviderResponseStatus.IN_PROGRESS: - return TspProviderResponseStatus.QUEUED - case NamaProviderResponseStatus.FAILED: - return TspProviderResponseStatus.FAILURE - default: - return TspProviderResponseStatus.QUEUED - } - } + async revoke( + payload: TspProviderRevokePayloadDto, + ): Promise { + const mappedRequest: NamaProviderRevokeRequestDto = + this.namaProviderUtils.mapRevokeToNamaRequestDto(payload) - private mapToNamaRequestDto( - payload: TspProviderSendPayloadDto, - ): NamaProviderRequestDto { - return { - uuid: payload.invoice_id, - economic_code: payload.economic_code, - fiscal_id: payload.fiscal_id, - payment: this.mapPayments(payload.payments), - header: { - ins: this.mapTspProviderRequestType(payload.type), - inp: this.mapInvoiceTemplate(payload.invoice_template), - inty: this.mapTspProviderCustomerType(payload.customer_type), - inno: payload.invoice_number.toString(), - tins: '', - indatim: payload.invoice_date.getTime() + '', - setm: '1', - ...this.mapCustomerInfo(payload.customer), - }, - body: payload.items.map(item => ({ - sstid: item.sku, - vra: item.sku_vat, - // sstt: item.unit_type, - fee: String(item.unit_price), - dis: String(item.discount), - mu: item.measure_unit, - am: String(item.quantity), - consfee: '0', - bros: '0', - spro: '0', - })), - } - } + try { + const response = await this.httpClient.request( + this.buildSendUrl(), + { + method: 'POST', + body: JSON.stringify(mappedRequest), + }, + this.createRequestInterceptors(payload.tsp_token), + ) + const providerResponse: NamaProviderRevokeResponseDto = await response.json() + this.logger.debug('NAMA provider response', providerResponse) - private mapTspProviderRequestType(type: TspProviderRequestType) { - switch (type) { - case TspProviderRequestType.MAIN: - return '1' - case TspProviderRequestType.UPDATE: - return '2' - case TspProviderRequestType.REVOKE: - return '3' - case TspProviderRequestType.REMOVE: - return '4' - } - } + const result: TspProviderRevokeResponseDto = { + invoice_id: payload.invoice_id, + request_payload: mappedRequest, + hasError: !response.ok, + message: providerResponse.message, + sent_at: new Date().toISOString(), + response_payload: providerResponse, + received_at: providerResponse.tsp_update_time, + tax_id: providerResponse.tax_id, + status: this.namaProviderUtils.mapResponseStatus( + providerResponse.status as NamaProviderResponseStatus, + ), + } - private mapInvoiceTemplate(template: InvoiceTemplateType) { - switch (template) { - case InvoiceTemplateType.SALE: - return '1' - case InvoiceTemplateType.FX_SALE: - return '2' - case InvoiceTemplateType.GOLD_JEWELRY: - return '3' - case InvoiceTemplateType.CONTRACT: - return '4' - case InvoiceTemplateType.UTILITY: - return '5' - case InvoiceTemplateType.AIR_TICKET: - return '6' - case InvoiceTemplateType.EXPORT: - return '7' - case InvoiceTemplateType.BILL_OF_LADING: - return '8' - case InvoiceTemplateType.PETROCHEMICAL: - return '9' - case InvoiceTemplateType.COMMODITY_EXCHANGE: - return '11' - case InvoiceTemplateType.INSURANCE: - return '13' + return result + } catch (err) { + this.logger.error('NAMA Revoke failed', err) + const failure: TspProviderRevokeResponseDto = { + invoice_id: payload.invoice_id, + request_payload: mappedRequest, + hasError: true, + message: (err as Error).message, + sent_at: new Date().toISOString(), + received_at: new Date().toISOString(), + tax_id: '', + status: TspProviderResponseStatus.FAILURE, + } + return failure } } - - private mapTspProviderCustomerType(type?: TspProviderCustomerType) { - switch (type) { - case TspProviderCustomerType.Unknown: - return '1' - case TspProviderCustomerType.Known: - return '2' - default: - return '3' - } - } - - private mapCustomerType(type?: CustomerType) { - switch (type) { - case CustomerType.INDIVIDUAL: - return '1' - case CustomerType.LEGAL: - return '2' - default: - return '5' - } - } - - private mapCustomerInfo(customer?: CustomerInfoDto) { - const info = {} as any - info.tob = this.mapCustomerType(customer?.type) - if (customer?.type === CustomerType.LEGAL && customer.legal_info) { - info.name = customer.legal_info.name - info.bid = customer.legal_info.economic_code - info.address = '' - } else if (customer?.type === CustomerType.INDIVIDUAL && customer.individual_info) { - info.name = `${customer.individual_info?.first_name || ''} ${ - customer.individual_info?.last_name || '' - }`.trim() - info.bid = customer.individual_info.national_id - info.mobile = customer.individual_info.mobile_number - info.address = '' - } - return info - } - - private mapPaymentMethod(method: PaymentMethodType): number { - switch (method) { - case PaymentMethodType.CHEQUE: - return 1 - case PaymentMethodType.SET_OFF: - return 2 - case PaymentMethodType.CASH: - return 3 - case PaymentMethodType.TERMINAL: - return 4 - case PaymentMethodType.PAYMENT_GATEWAY: - return 5 - case PaymentMethodType.CARD: - return 6 - case PaymentMethodType.BANK: - return 7 - case PaymentMethodType.OTHER: - return 8 - } - } - - private mapPayments(payments: PaymentInfoDto[]): NamaProviderPaymentInfoDto[] { - return payments.map(payment => ({ - pmt: this.mapPaymentMethod(payment.payment_method), - pv: payment.amount, - trn: payment.tracking_code, - pcn: payment.card_number, - pdt: payment.paid_at ? String(payment.paid_at.getTime()) : undefined, - })) - } } diff --git a/src/modules/tspProviders/switch/nama/nama-provider.dto.ts b/src/modules/tspProviders/switch/nama/nama-provider.dto.ts index 5f7d332..b1b4124 100644 --- a/src/modules/tspProviders/switch/nama/nama-provider.dto.ts +++ b/src/modules/tspProviders/switch/nama/nama-provider.dto.ts @@ -5,6 +5,7 @@ import { IsArray, IsEnum, IsNumber, + IsObject, IsOptional, IsString, Min, @@ -46,11 +47,14 @@ export class NamaProviderPaymentInfoDto { } export class NamaProviderBodyItemDto { - @ApiProperty() + @ApiProperty({ required: true, description: 'شناسه کالا / خدمت' }) @IsString() sstid: string - @ApiProperty() + @ApiProperty({ + required: true, + description: `نرخ مالیات بر ارزش افزوده`, + }) @IsString() vra: string @@ -58,45 +62,63 @@ export class NamaProviderBodyItemDto { // @IsString() // sstt: string - @ApiProperty() + @ApiProperty({ + required: true, + description: 'مبلغ واحد', + }) @IsString() fee: string - @ApiProperty() + @ApiProperty({ + required: true, + description: 'مبلغ تخفیف', + }) @IsString() dis: string - @ApiProperty() + @ApiProperty({ + required: true, + description: 'واحد اندازه گیری', + }) @IsString() mu: string - @ApiProperty() + @ApiProperty({ + required: true, + description: 'تعداد / مقدار', + }) @IsString() am: string - @ApiProperty() + @ApiProperty({ + description: ' اجرت ساخت (طلا)', + }) @IsString() consfee: string - @ApiProperty() + @ApiProperty({ + description: 'حق العمل', + }) @IsString() bros: string - @ApiProperty() + @ApiProperty({ + description: 'سود فروشنده', + }) @IsString() spro: string } export class NamaProviderHeaderDto { - @ApiProperty({ required: true }) + @ApiProperty({ required: true, description: 'موضوع صورتحساب' }) @IsString() ins: string - @ApiProperty() + @ApiProperty({ required: true, description: 'الگوی صورتحساب' }) @IsString() inp: string - @ApiProperty({ required: true }) + @ApiProperty({ required: true, description: 'نوع صورتحساب' }) @IsString() inty: string @@ -104,41 +126,46 @@ export class NamaProviderHeaderDto { // @IsString() // unique_tax_code: string - @ApiProperty({ required: true }) + @ApiProperty({ required: true, description: 'سریال صورتحساب داخلی حافظه مالیاتی' }) @IsString() inno: string - @ApiProperty({ required: true }) - @IsString() - tins: string + // @ApiProperty({ required: true }) + // @IsString() + // tins: string - @ApiProperty({ required: true }) + @ApiProperty({ + required: true, + description: 'تاریخ و زمان صدور صورتحساب به صورت timestamp', + }) @IsString() indatim: string - @ApiProperty({ required: true }) + @ApiProperty({ required: true, description: 'نام مشتری' }) @IsString() name: string - @ApiProperty({ required: true }) + @ApiProperty({ required: true, description: 'نوع شخصیت خریدار' }) @IsString() tob: string - @ApiProperty() + @ApiProperty({ description: 'آدرس' }) @IsOptional() @IsString() address?: string - @ApiProperty() + @ApiProperty({ description: 'شماره موبایل' }) @IsOptional() @IsString() mobile?: string - @ApiProperty() + @ApiProperty({ + description: `شماره ملی / شناسه ملی / شناسه مشارکت مدنی / کد فراگیر خریدار`, + }) @IsString() bid: string - @ApiProperty({ required: true }) + @ApiProperty({ required: true, description: 'روش تسویه' }) @IsString() setm: string } @@ -259,3 +286,90 @@ export class NamaProviderGetResponseDto { @IsString() tsp_update_time: string } + +export class NamaProviderRevokeHeaderDto { + @ApiProperty({ required: true, description: 'موضوع صورتحساب' }) + @IsString() + ins: string + + @ApiProperty({ required: true, description: 'سریال صورتحساب داخلی حافظه مالیاتی' }) + @IsString() + inno: string + + @ApiProperty({ + required: true, + description: 'آخرین شماره مالیاتی دریافت شده مربوط به فاکتور', + }) + @IsString() + irtaxid: string +} +export class NamaProviderRevokeRequestDto { + // @ApiProperty({ type: [NamaProviderBodyItemDto] }) + // @IsArray() + // @ValidateNested({ each: true }) + // @Type(() => NamaProviderBodyItemDto) + // body: NamaProviderBodyItemDto[] + + // @ApiProperty({ type: [NamaProviderPaymentInfoDto] }) + // @IsArray() + // @ValidateNested({ each: true }) + // @Type(() => NamaProviderPaymentInfoDto) + // payment: NamaProviderPaymentInfoDto[] + @ApiProperty({ type: Object, required: true }) + @IsObject() + body: {} + + @ApiProperty({ type: NamaProviderRevokeHeaderDto }) + @ValidateNested() + @Type(() => NamaProviderRevokeHeaderDto) + header: NamaProviderRevokeHeaderDto + + @ApiProperty() + @IsString() + uuid: string + + @ApiProperty() + @IsString() + economic_code: string + + @ApiProperty() + @IsString() + fiscal_id: string +} + +export class NamaProviderRevokeResponseDto { + @ApiProperty() + @IsString() + uuid: string + + @ApiProperty() + @IsString() + message: string + + @ApiProperty() + @IsString() + status: NamaProviderResponseStatus + + @ApiProperty() + @IsString() + tax_id: string + + @ApiProperty() + @IsString() + inno: string + + @ApiProperty({ required: true }) + @IsString() + reference_number: string + + @ApiProperty({ type: () => NamaProviderApiErrorResponseDto, required: false }) + @IsOptional() + @ValidateNested() + @Type(() => NamaProviderApiErrorResponseDto) + tax_api_response?: NamaProviderApiErrorResponseDto + + @ApiProperty({ required: false }) + @IsOptional() + @IsString() + tsp_update_time: string +} diff --git a/src/modules/tspProviders/switch/nama/nama-provider.util.ts b/src/modules/tspProviders/switch/nama/nama-provider.util.ts new file mode 100644 index 0000000..b768a9f --- /dev/null +++ b/src/modules/tspProviders/switch/nama/nama-provider.util.ts @@ -0,0 +1,195 @@ +import { + CustomerType, + InvoiceTemplateType, + PaymentMethodType, + TspProviderCustomerType, + TspProviderRequestType, + TspProviderResponseStatus, +} from '@/generated/prisma/enums' +import { + CustomerInfoDto, + PaymentInfoDto, + TspProviderRevokePayloadDto, + TspProviderSendPayloadDto, +} from '../../dto/provider-switch.dto' +import { + NamaProviderPaymentInfoDto, + NamaProviderRequestDto, + NamaProviderResponseStatus, + NamaProviderRevokeRequestDto, +} from './nama-provider.dto' + +export class NamaProviderUtils { + mapResponseStatus(status: NamaProviderResponseStatus): TspProviderResponseStatus { + switch (status.toUpperCase()) { + case NamaProviderResponseStatus.SUCCESS: + case NamaProviderResponseStatus.POSTED: + return TspProviderResponseStatus.SUCCESS + case NamaProviderResponseStatus.PENDING: + case NamaProviderResponseStatus.IN_PROGRESS: + return TspProviderResponseStatus.QUEUED + case NamaProviderResponseStatus.FAILED: + return TspProviderResponseStatus.FAILURE + default: + return TspProviderResponseStatus.QUEUED + } + } + + mapToNamaRequestDto(payload: TspProviderSendPayloadDto): NamaProviderRequestDto { + return { + uuid: payload.invoice_id, + economic_code: payload.economic_code, + fiscal_id: payload.fiscal_id, + payment: this.mapPayments(payload.payments), + header: { + ins: this.mapTspProviderRequestType(payload.type), + inp: this.mapInvoiceTemplate(payload.invoice_template), + inty: this.mapTspProviderCustomerType(payload.customer_type), + inno: payload.invoice_number.toString(), + tins: '', + indatim: payload.invoice_date.getTime() + '', + setm: '1', + ...this.mapCustomerInfo(payload.customer), + }, + body: payload.items.map(item => ({ + sstid: item.sku, + vra: item.sku_vat, + // sstt: item.unit_type, + fee: String(item.unit_price), + dis: String(item.discount), + mu: item.measure_unit, + am: String(item.quantity), + consfee: '0', + bros: '0', + spro: '0', + })), + } + } + + mapRevokeToNamaRequestDto( + payload: TspProviderRevokePayloadDto, + ): NamaProviderRevokeRequestDto { + return { + uuid: payload.invoice_id, + economic_code: payload.economic_code, + fiscal_id: payload.fiscal_id, + header: { + inno: payload.invoice_number.toString(), + ins: this.mapTspProviderRequestType(TspProviderRequestType.REVOKE), + irtaxid: payload.last_attempt_tax_id, + }, + body: {}, + } + } + + private mapTspProviderRequestType(type: TspProviderRequestType) { + switch (type) { + case TspProviderRequestType.MAIN: + return '1' + case TspProviderRequestType.UPDATE: + return '2' + case TspProviderRequestType.REVOKE: + return '3' + case TspProviderRequestType.RETURN: + return '4' + } + } + + private mapInvoiceTemplate(template: InvoiceTemplateType) { + switch (template) { + case InvoiceTemplateType.SALE: + return '1' + case InvoiceTemplateType.FX_SALE: + return '2' + case InvoiceTemplateType.GOLD_JEWELRY: + return '3' + case InvoiceTemplateType.CONTRACT: + return '4' + case InvoiceTemplateType.UTILITY: + return '5' + case InvoiceTemplateType.AIR_TICKET: + return '6' + case InvoiceTemplateType.EXPORT: + return '7' + case InvoiceTemplateType.BILL_OF_LADING: + return '8' + case InvoiceTemplateType.PETROCHEMICAL: + return '9' + case InvoiceTemplateType.COMMODITY_EXCHANGE: + return '11' + case InvoiceTemplateType.INSURANCE: + return '13' + } + } + + private mapTspProviderCustomerType(type?: TspProviderCustomerType) { + switch (type) { + case TspProviderCustomerType.Known: + return '1' + case TspProviderCustomerType.Unknown: + return '2' + default: + return '3' + } + } + + private mapCustomerType(type?: CustomerType) { + switch (type) { + case CustomerType.INDIVIDUAL: + return '1' + case CustomerType.LEGAL: + return '2' + default: + return '5' + } + } + + private mapCustomerInfo(customer?: CustomerInfoDto) { + const info = {} as any + info.tob = this.mapCustomerType(customer?.type) + if (customer?.type === CustomerType.LEGAL && customer.legal_info) { + info.name = customer.legal_info.name + info.bid = customer.legal_info.economic_code + info.address = '' + } else if (customer?.type === CustomerType.INDIVIDUAL && customer.individual_info) { + info.name = `${customer.individual_info?.first_name || ''} ${ + customer.individual_info?.last_name || '' + }`.trim() + info.bid = customer.individual_info.national_id + info.mobile = customer.individual_info.mobile_number + info.address = '' + } + return info + } + + private mapPaymentMethod(method: PaymentMethodType): number { + switch (method) { + case PaymentMethodType.CHEQUE: + return 1 + case PaymentMethodType.SET_OFF: + return 2 + case PaymentMethodType.CASH: + return 3 + case PaymentMethodType.TERMINAL: + return 4 + case PaymentMethodType.PAYMENT_GATEWAY: + return 5 + case PaymentMethodType.CARD: + return 6 + case PaymentMethodType.BANK: + return 7 + case PaymentMethodType.OTHER: + return 8 + } + } + + private mapPayments(payments: PaymentInfoDto[]): NamaProviderPaymentInfoDto[] { + return payments.map(payment => ({ + pmt: this.mapPaymentMethod(payment.payment_method), + pv: payment.amount, + trn: payment.tracking_code, + pcn: payment.card_number, + pdt: payment.paid_at ? String(payment.paid_at.getTime()) : undefined, + })) + } +}