invoice number
This commit is contained in:
@@ -823,25 +823,29 @@
|
||||
"create_invoice",
|
||||
"update_invoice",
|
||||
"delete_invoice",
|
||||
"view_all_invoiced_orders",
|
||||
"view_my_assigned_invoiced_requests",
|
||||
"view_orders",
|
||||
"view_assigned_orders",
|
||||
"create_order",
|
||||
"update_order",
|
||||
"assign_designer",
|
||||
"delete_order",
|
||||
"create_user",
|
||||
"update_user",
|
||||
"delete_user",
|
||||
"view_users",
|
||||
"manage_admins",
|
||||
"manage_roles",
|
||||
"manage_users",
|
||||
"manage_payments",
|
||||
"manage_settings",
|
||||
"manage_form_builder",
|
||||
"create_print",
|
||||
"view_print",
|
||||
"manage_learnings",
|
||||
"manage_criticisms",
|
||||
"manage_announcements"
|
||||
"manage_announcements",
|
||||
"manage_tickets",
|
||||
"new_request_notification",
|
||||
"new_payment_notification",
|
||||
"new_ticket_notification"
|
||||
],
|
||||
"mappedType": "enum"
|
||||
},
|
||||
@@ -1367,101 +1371,6 @@
|
||||
},
|
||||
"nativeEnums": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"admin_id": {
|
||||
"name": "admin_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"events": {
|
||||
"name": "events",
|
||||
"type": "jsonb",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "json"
|
||||
}
|
||||
},
|
||||
"name": "notification_preferences",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"columnNames": [
|
||||
"admin_id"
|
||||
],
|
||||
"composite": false,
|
||||
"keyName": "notification_preferences_admin_id_unique",
|
||||
"constraint": true,
|
||||
"primary": false,
|
||||
"unique": true
|
||||
},
|
||||
{
|
||||
"keyName": "notification_preferences_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"constraint": true,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {
|
||||
"notification_preferences_admin_id_foreign": {
|
||||
"constraintName": "notification_preferences_admin_id_foreign",
|
||||
"columnNames": [
|
||||
"admin_id"
|
||||
],
|
||||
"localTableName": "public.notification_preferences",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.admins",
|
||||
"deleteRule": "cascade",
|
||||
"updateRule": "cascade"
|
||||
}
|
||||
},
|
||||
"nativeEnums": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"role_id": {
|
||||
@@ -1723,74 +1632,6 @@
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"admin_id": {
|
||||
"name": "admin_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"attachments": {
|
||||
"name": "attachments",
|
||||
"type": "jsonb",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "json"
|
||||
},
|
||||
"ref_id": {
|
||||
"name": "ref_id",
|
||||
"type": "varchar(255)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 255,
|
||||
"mappedType": "string"
|
||||
},
|
||||
"parent_id": {
|
||||
"name": "parent_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
@@ -1802,8 +1643,8 @@
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"read_at": {
|
||||
"name": "read_at",
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
@@ -1811,13 +1652,87 @@
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"parent_id": {
|
||||
"name": "parent_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"subject": {
|
||||
"name": "subject",
|
||||
"type": "varchar(255)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 255,
|
||||
"mappedType": "string"
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "varchar(255)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 255,
|
||||
"mappedType": "string"
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"enumItems": [
|
||||
"open",
|
||||
"closed",
|
||||
"pending",
|
||||
"in_progress"
|
||||
],
|
||||
"mappedType": "enum"
|
||||
},
|
||||
"attachments": {
|
||||
"name": "attachments",
|
||||
"type": "text[]",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "array"
|
||||
},
|
||||
"admin_id": {
|
||||
"name": "admin_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
}
|
||||
},
|
||||
"name": "ticket",
|
||||
"name": "tickets",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "ticket_pkey",
|
||||
"keyName": "tickets_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
@@ -1829,25 +1744,25 @@
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {
|
||||
"ticket_user_id_foreign": {
|
||||
"constraintName": "ticket_user_id_foreign",
|
||||
"tickets_parent_id_foreign": {
|
||||
"constraintName": "tickets_parent_id_foreign",
|
||||
"columnNames": [
|
||||
"user_id"
|
||||
"parent_id"
|
||||
],
|
||||
"localTableName": "public.ticket",
|
||||
"localTableName": "public.tickets",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.users",
|
||||
"referencedTableName": "public.tickets",
|
||||
"deleteRule": "set null",
|
||||
"updateRule": "cascade"
|
||||
},
|
||||
"ticket_admin_id_foreign": {
|
||||
"constraintName": "ticket_admin_id_foreign",
|
||||
"tickets_admin_id_foreign": {
|
||||
"constraintName": "tickets_admin_id_foreign",
|
||||
"columnNames": [
|
||||
"admin_id"
|
||||
],
|
||||
"localTableName": "public.ticket",
|
||||
"localTableName": "public.tickets",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
@@ -1855,16 +1770,16 @@
|
||||
"deleteRule": "set null",
|
||||
"updateRule": "cascade"
|
||||
},
|
||||
"ticket_parent_id_foreign": {
|
||||
"constraintName": "ticket_parent_id_foreign",
|
||||
"tickets_user_id_foreign": {
|
||||
"constraintName": "tickets_user_id_foreign",
|
||||
"columnNames": [
|
||||
"parent_id"
|
||||
"user_id"
|
||||
],
|
||||
"localTableName": "public.ticket",
|
||||
"localTableName": "public.tickets",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.ticket",
|
||||
"referencedTableName": "public.users",
|
||||
"deleteRule": "set null",
|
||||
"updateRule": "cascade"
|
||||
}
|
||||
@@ -2174,11 +2089,13 @@
|
||||
"nullable": false,
|
||||
"enumItems": [
|
||||
"newRequest",
|
||||
"invoiced",
|
||||
"newInvoice",
|
||||
"newPayment",
|
||||
"newOrder",
|
||||
"designerAssign",
|
||||
"paymentSuccess",
|
||||
"newCriticism"
|
||||
"newCriticism",
|
||||
"newTicket",
|
||||
"newOrderMessage",
|
||||
"newRequestMessage"
|
||||
],
|
||||
"mappedType": "enum"
|
||||
},
|
||||
@@ -2411,9 +2328,9 @@
|
||||
},
|
||||
"invoice_number": {
|
||||
"name": "invoice_number",
|
||||
"type": "serial",
|
||||
"unsigned": true,
|
||||
"autoincrement": true,
|
||||
"type": "int",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
@@ -2424,7 +2341,7 @@
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"sub_total": {
|
||||
@@ -2433,7 +2350,7 @@
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"tax_amount": {
|
||||
@@ -2442,7 +2359,7 @@
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"total": {
|
||||
@@ -2451,7 +2368,7 @@
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"paid_amount": {
|
||||
@@ -2471,7 +2388,6 @@
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"default": "0",
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"enable_tax": {
|
||||
@@ -2526,6 +2442,16 @@
|
||||
"name": "invoices",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"columnNames": [
|
||||
"invoice_number"
|
||||
],
|
||||
"composite": false,
|
||||
"keyName": "invoices_invoice_number_unique",
|
||||
"constraint": true,
|
||||
"primary": false,
|
||||
"unique": true
|
||||
},
|
||||
{
|
||||
"keyName": "invoices_user_id_index",
|
||||
"columnNames": [
|
||||
@@ -2886,15 +2812,6 @@
|
||||
"nullable": false,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"sub_total": {
|
||||
"name": "sub_total",
|
||||
"type": "int",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"discount": {
|
||||
"name": "discount",
|
||||
"type": "int",
|
||||
@@ -2904,15 +2821,6 @@
|
||||
"nullable": true,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"total": {
|
||||
"name": "total",
|
||||
"type": "int",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "integer"
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
@@ -3588,6 +3496,166 @@
|
||||
},
|
||||
"nativeEnums": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"admin_id": {
|
||||
"name": "admin_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"attachments": {
|
||||
"name": "attachments",
|
||||
"type": "jsonb",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "json"
|
||||
},
|
||||
"ref_id": {
|
||||
"name": "ref_id",
|
||||
"type": "varchar(255)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 255,
|
||||
"mappedType": "string"
|
||||
},
|
||||
"parent_id": {
|
||||
"name": "parent_id",
|
||||
"type": "char(26)",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 26,
|
||||
"mappedType": "character"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"length": 6,
|
||||
"default": "now()",
|
||||
"mappedType": "datetime"
|
||||
},
|
||||
"read_at": {
|
||||
"name": "read_at",
|
||||
"type": "timestamptz",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"length": 6,
|
||||
"mappedType": "datetime"
|
||||
}
|
||||
},
|
||||
"name": "chat",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "chat_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"constraint": true,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {
|
||||
"chat_user_id_foreign": {
|
||||
"constraintName": "chat_user_id_foreign",
|
||||
"columnNames": [
|
||||
"user_id"
|
||||
],
|
||||
"localTableName": "public.chat",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.users",
|
||||
"deleteRule": "set null",
|
||||
"updateRule": "cascade"
|
||||
},
|
||||
"chat_admin_id_foreign": {
|
||||
"constraintName": "chat_admin_id_foreign",
|
||||
"columnNames": [
|
||||
"admin_id"
|
||||
],
|
||||
"localTableName": "public.chat",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.admins",
|
||||
"deleteRule": "set null",
|
||||
"updateRule": "cascade"
|
||||
},
|
||||
"chat_parent_id_foreign": {
|
||||
"constraintName": "chat_parent_id_foreign",
|
||||
"columnNames": [
|
||||
"parent_id"
|
||||
],
|
||||
"localTableName": "public.chat",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.chat",
|
||||
"deleteRule": "set null",
|
||||
"updateRule": "cascade"
|
||||
}
|
||||
},
|
||||
"nativeEnums": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20260222084735 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`create table "learning_categories" ("id" char(26) not null, "created_at" timestamptz not null default now(), "deleted_at" timestamptz null, "name" varchar(100) not null, constraint "learning_categories_pkey" primary key ("id"));`);
|
||||
this.addSql(`alter table "learning_categories" add constraint "learning_categories_name_unique" unique ("name");`);
|
||||
|
||||
this.addSql(`create table "learnings" ("id" char(26) not null, "created_at" timestamptz not null default now(), "deleted_at" timestamptz null, "title" varchar(200) not null, "description" text not null, "cover_url" text not null, "video_url" text null, "video_duration" varchar(200) null, "category_id" char(26) not null, constraint "learnings_pkey" primary key ("id"));`);
|
||||
|
||||
this.addSql(`create table "prints" ("id" char(26) not null, "created_at" timestamptz not null default now(), "deleted_at" timestamptz null, "fileds" jsonb null, constraint "prints_pkey" primary key ("id"));`);
|
||||
|
||||
this.addSql(`create table "learning_progress" ("id" char(26) not null, "created_at" timestamptz not null default now(), "deleted_at" timestamptz null, "user_id" char(26) not null, "learning_id" char(26) not null, "watched_at" timestamptz not null default CURRENT_TIMESTAMP, constraint "learning_progress_pkey" primary key ("id"));`);
|
||||
|
||||
this.addSql(`alter table "learnings" add constraint "learnings_category_id_foreign" foreign key ("category_id") references "learning_categories" ("id") on update cascade;`);
|
||||
|
||||
this.addSql(`alter table "learning_progress" add constraint "learning_progress_user_id_foreign" foreign key ("user_id") references "users" ("id") on update cascade;`);
|
||||
this.addSql(`alter table "learning_progress" add constraint "learning_progress_learning_id_foreign" foreign key ("learning_id") references "learnings" ("id") on update cascade;`);
|
||||
|
||||
this.addSql(`alter table "permissions" drop constraint if exists "permissions_name_check";`);
|
||||
|
||||
this.addSql(`alter table "permissions" add constraint "permissions_name_check" check("name" in ('manage_products', 'manage_categories', 'view_requests', 'delete_request', 'update_request', 'view_invoices', 'create_invoice', 'update_invoice', 'delete_invoice', 'view_all_invoiced_orders', 'view_my_assigned_invoiced_requests', 'view_orders', 'view_assigned_orders', 'create_order', 'update_order', 'assign_designer', 'delete_order', 'manage_admins', 'manage_roles', 'manage_users', 'manage_payments', 'manage_settings', 'manage_form_builder', 'create_print', 'view_print', 'manage_learnings'));`);
|
||||
|
||||
this.addSql(`alter table "orders" add column "print_id" char(26) null;`);
|
||||
this.addSql(`alter table "orders" add constraint "orders_print_id_foreign" foreign key ("print_id") references "prints" ("id") on update cascade on delete set null;`);
|
||||
this.addSql(`alter table "orders" add constraint "orders_print_id_unique" unique ("print_id");`);
|
||||
|
||||
this.addSql(`alter table "credit_transactions" rename column "order_id" to "invoice_id";`);
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(`alter table "permissions" drop constraint if exists "permissions_name_check";`);
|
||||
|
||||
this.addSql(`alter table "permissions" add constraint "permissions_name_check" check("name" in ('manage_products', 'manage_categories', 'view_requests', 'delete_request', 'update_request', 'view_invoices', 'create_invoice', 'update_invoice', 'delete_invoice', 'view_all_invoiced_orders', 'view_my_assigned_invoiced_requests', 'view_orders', 'view_assigned_orders', 'create_order', 'update_order', 'assign_designer', 'delete_order', 'manage_admins', 'manage_roles', 'manage_users', 'manage_payments', 'manage_settings', 'manage_form_builder', 'manage_print'));`);
|
||||
|
||||
this.addSql(`alter table "orders" drop constraint "orders_print_id_unique";`);
|
||||
|
||||
this.addSql(`alter table "orders" add column "attributes" jsonb null, add column "printery" varchar(255) null, add column "lithography" varchar(255) null;`);
|
||||
|
||||
this.addSql(`alter table "credit_transactions" rename column "invoice_id" to "order_id";`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20260222092921 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`create table "announcements" ("id" char(26) not null, "created_at" timestamptz not null default now(), "deleted_at" timestamptz null, "title" varchar(100) not null, "content" text not null, "publish_at" timestamptz null, "is_important" boolean not null default false, "is_public" boolean not null default false, constraint "announcements_pkey" primary key ("id"));`);
|
||||
this.addSql(`create index "announcements_is_public_created_at_index" on "announcements" ("is_public", "created_at");`);
|
||||
|
||||
this.addSql(`create table "user_announcements" ("id" char(26) not null, "created_at" timestamptz not null default now(), "deleted_at" timestamptz null, "user_id" char(26) not null, "announcement_id" char(26) not null, "is_read" boolean not null default false, constraint "user_announcements_pkey" primary key ("id"));`);
|
||||
|
||||
this.addSql(`alter table "user_announcements" add constraint "user_announcements_user_id_foreign" foreign key ("user_id") references "users" ("id") on update cascade on delete cascade;`);
|
||||
this.addSql(`alter table "user_announcements" add constraint "user_announcements_announcement_id_foreign" foreign key ("announcement_id") references "announcements" ("id") on update cascade on delete cascade;`);
|
||||
|
||||
this.addSql(`alter table "permissions" drop constraint if exists "permissions_name_check";`);
|
||||
|
||||
this.addSql(`alter table "permissions" add constraint "permissions_name_check" check("name" in ('manage_products', 'manage_categories', 'view_requests', 'delete_request', 'update_request', 'view_invoices', 'create_invoice', 'update_invoice', 'delete_invoice', 'view_all_invoiced_orders', 'view_my_assigned_invoiced_requests', 'view_orders', 'view_assigned_orders', 'create_order', 'update_order', 'assign_designer', 'delete_order', 'manage_admins', 'manage_roles', 'manage_users', 'manage_payments', 'manage_settings', 'manage_form_builder', 'create_print', 'view_print', 'manage_learnings', 'manage_criticisms', 'manage_announcements'));`);
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(`alter table "permissions" drop constraint if exists "permissions_name_check";`);
|
||||
this.addSql(`alter table "permissions" add constraint "permissions_name_check" check("name" in ('manage_products', 'manage_categories', 'view_requests', 'delete_request', 'update_request', 'view_invoices', 'create_invoice', 'update_invoice', 'delete_invoice', 'view_all_invoiced_orders', 'view_my_assigned_invoiced_requests', 'view_orders', 'view_assigned_orders', 'create_order', 'update_order', 'assign_designer', 'delete_order', 'manage_admins', 'manage_roles', 'manage_users', 'manage_payments', 'manage_settings', 'manage_form_builder', 'create_print', 'view_print', 'manage_learnings', 'manage_criticisms'));`);
|
||||
|
||||
this.addSql(`drop table if exists "user_announcements";`);
|
||||
this.addSql(`drop table if exists "announcements";`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20260404082727 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`alter table "credit_transactions" drop constraint if exists "credit_transactions_type_check";`);
|
||||
|
||||
this.addSql(`alter table "credit_transactions" add constraint "credit_transactions_type_check" check("type" in (''));`);
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(`alter table "credit_transactions" drop constraint if exists "credit_transactions_type_check";`);
|
||||
|
||||
this.addSql(`alter table "credit_transactions" add constraint "credit_transactions_type_check" check("type" in (''));`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20260404083020 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
//recalc_invoice_totals
|
||||
this.addSql(`
|
||||
CREATE OR REPLACE FUNCTION recalc_invoice_totals()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
v_invoice_id char(26);
|
||||
v_subtotal int;
|
||||
v_discount int;
|
||||
v_tax int;
|
||||
v_total int;
|
||||
v_paid int;
|
||||
v_enable_tax boolean;
|
||||
BEGIN
|
||||
|
||||
v_invoice_id := COALESCE(NEW.invoice_id, OLD.invoice_id);
|
||||
|
||||
SELECT
|
||||
COALESCE(SUM(sub_total),0),
|
||||
COALESCE(SUM(discount),0)
|
||||
INTO
|
||||
v_subtotal,
|
||||
v_discount
|
||||
FROM invoice_items
|
||||
WHERE invoice_id = v_invoice_id
|
||||
AND deleted_at IS NULL;
|
||||
|
||||
SELECT enable_tax
|
||||
INTO v_enable_tax
|
||||
FROM invoices
|
||||
WHERE id = v_invoice_id;
|
||||
|
||||
IF v_enable_tax THEN
|
||||
v_tax := (v_subtotal - v_discount) * 0.10;
|
||||
ELSE
|
||||
v_tax := 0;
|
||||
END IF;
|
||||
|
||||
v_total := (v_subtotal - v_discount) + v_tax;
|
||||
|
||||
SELECT COALESCE(SUM(amount),0)
|
||||
INTO v_paid
|
||||
FROM payments
|
||||
WHERE invoice_id = v_invoice_id
|
||||
AND status = 'SUCCESS';
|
||||
|
||||
UPDATE invoices
|
||||
SET
|
||||
sub_total = v_subtotal,
|
||||
discount = v_discount,
|
||||
tax_amount = v_tax,
|
||||
total = v_total,
|
||||
paid_amount = v_paid,
|
||||
balance = v_total - v_paid
|
||||
WHERE id = v_invoice_id;
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
`);
|
||||
|
||||
// trigger
|
||||
this.addSql(`
|
||||
CREATE TRIGGER trg_invoice_items_recalc
|
||||
AFTER INSERT OR UPDATE OR DELETE
|
||||
ON invoice_items
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION recalc_invoice_totals();
|
||||
`);
|
||||
|
||||
// recalc_invoice_payments
|
||||
this.addSql(`
|
||||
CREATE OR REPLACE FUNCTION recalc_invoice_payments()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
v_invoice_id char(26);
|
||||
v_paid int;
|
||||
v_total int;
|
||||
BEGIN
|
||||
|
||||
v_invoice_id := COALESCE(NEW.invoice_id, OLD.invoice_id);
|
||||
|
||||
SELECT COALESCE(SUM(amount),0)
|
||||
INTO v_paid
|
||||
FROM payments
|
||||
WHERE invoice_id = v_invoice_id
|
||||
AND status = 'paid';
|
||||
|
||||
SELECT total
|
||||
INTO v_total
|
||||
FROM invoices
|
||||
WHERE id = v_invoice_id;
|
||||
|
||||
UPDATE invoices
|
||||
SET
|
||||
paid_amount = v_paid,
|
||||
balance = v_total - v_paid
|
||||
WHERE id = v_invoice_id;
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
`);
|
||||
|
||||
// trigger
|
||||
this.addSql(`
|
||||
CREATE TRIGGER trg_payments_recalc
|
||||
AFTER INSERT OR UPDATE OR DELETE
|
||||
ON payments
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION recalc_invoice_payments();
|
||||
`);
|
||||
|
||||
this.addSql(`CREATE SEQUENCE invoice_number_seq START 1;`);
|
||||
|
||||
this.addSql(`
|
||||
ALTER TABLE invoices
|
||||
ALTER COLUMN invoice_number
|
||||
SET DEFAULT nextval('invoice_number_seq');
|
||||
`);
|
||||
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
|
||||
this.addSql(`DROP TRIGGER IF EXISTS trg_invoice_items_recalc ON invoice_items;`);
|
||||
this.addSql(`DROP TRIGGER IF EXISTS trg_payments_recalc ON payments;`);
|
||||
|
||||
this.addSql(`DROP FUNCTION IF EXISTS recalc_invoice_totals;`);
|
||||
this.addSql(`DROP FUNCTION IF EXISTS recalc_invoice_payments;`);
|
||||
|
||||
|
||||
// remove default from invoice_number
|
||||
this.addSql(`
|
||||
ALTER TABLE invoices
|
||||
ALTER COLUMN invoice_number
|
||||
DROP DEFAULT;
|
||||
`);
|
||||
|
||||
// drop sequence
|
||||
this.addSql(`DROP SEQUENCE IF EXISTS invoice_number_seq;`);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20260404112450 extends Migration {
|
||||
|
||||
override async up(): Promise<void> {
|
||||
this.addSql(`alter table "invoices" alter column "invoice_number" type int using ("invoice_number"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "discount" type int using ("discount"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "discount" set not null;`);
|
||||
this.addSql(`alter table "invoices" alter column "sub_total" type int using ("sub_total"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "sub_total" set not null;`);
|
||||
this.addSql(`alter table "invoices" alter column "tax_amount" type int using ("tax_amount"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "tax_amount" set not null;`);
|
||||
this.addSql(`alter table "invoices" alter column "total" type int using ("total"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "total" set not null;`);
|
||||
this.addSql(`alter table "invoices" alter column "balance" drop default;`);
|
||||
this.addSql(`alter table "invoices" alter column "balance" type int using ("balance"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "invoice_number" drop default;`);
|
||||
this.addSql(`alter table "invoices" add constraint "invoices_invoice_number_unique" unique ("invoice_number");`);
|
||||
}
|
||||
|
||||
override async down(): Promise<void> {
|
||||
this.addSql(`alter table "invoices" drop constraint "invoices_invoice_number_unique";`);
|
||||
|
||||
this.addSql(`alter table "invoices" alter column "invoice_number" type int using ("invoice_number"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "discount" type int using ("discount"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "discount" drop not null;`);
|
||||
this.addSql(`alter table "invoices" alter column "sub_total" type int using ("sub_total"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "sub_total" drop not null;`);
|
||||
this.addSql(`alter table "invoices" alter column "tax_amount" type int using ("tax_amount"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "tax_amount" drop not null;`);
|
||||
this.addSql(`alter table "invoices" alter column "total" type int using ("total"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "total" drop not null;`);
|
||||
this.addSql(`alter table "invoices" alter column "balance" type int using ("balance"::int);`);
|
||||
this.addSql(`alter table "invoices" alter column "balance" set default 0;`);
|
||||
this.addSql(`create sequence if not exists "invoices_invoice_number_seq";`);
|
||||
this.addSql(`select setval('invoices_invoice_number_seq', (select max("invoice_number") from "invoices"));`);
|
||||
this.addSql(`alter table "invoices" alter column "invoice_number" set default nextval('invoices_invoice_number_seq');`);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,6 +54,7 @@ export class AuthGuard implements CanActivate {
|
||||
throw new UnauthorizedException('Invalid or expired token');
|
||||
}
|
||||
}
|
||||
|
||||
private extractTokenFromHeader(request: Request): string | undefined {
|
||||
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
||||
return type === 'Bearer' ? token : undefined;
|
||||
|
||||
@@ -8,16 +8,21 @@ import { NotifChannelEnum, NotifTitle } from 'src/modules/notification/interface
|
||||
import { ChatCreatedByAdminEvent } from '../events/chat.events';
|
||||
import { PermissionEnum } from 'src/common/enums/permission.enum';
|
||||
import { AdminRepository } from 'src/modules/admin/repositories/admin.repository';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
@Injectable()
|
||||
export class ChatListeners {
|
||||
private readonly logger = new Logger(ChatListeners.name);
|
||||
private newChatSmsTemplateId: string;
|
||||
|
||||
constructor(
|
||||
private readonly em: EntityManager,
|
||||
private readonly notificationService: NotificationService,
|
||||
private readonly adminRepository: AdminRepository,
|
||||
) { }
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
this.newChatSmsTemplateId = this.configService.get<string>('SMS_PATTERN_NEW_CHAT') ?? 'new-chat';
|
||||
}
|
||||
|
||||
@OnEvent(ChatCreatedByAdminEvent.name)
|
||||
async handleChatCreatedByAdmin(event: ChatCreatedByAdminEvent) {
|
||||
@@ -43,7 +48,7 @@ export class ChatListeners {
|
||||
title: NotifTitle.NEW_TICKET,
|
||||
content: body,
|
||||
sms: {
|
||||
templateId: '',
|
||||
templateId: this.newChatSmsTemplateId,
|
||||
parameters: {},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Collection, Entity, ManyToOne, OptionalProps, Property,OneToMany } from '@mikro-orm/core';
|
||||
import { Collection, Entity, ManyToOne, OptionalProps, Property, OneToMany, Opt } from '@mikro-orm/core';
|
||||
import { Product } from 'src/modules/product/entities/product.entity';
|
||||
import { BaseEntity } from 'src/common/entities/base.entity';
|
||||
import { Invoice } from './invoice.entity';
|
||||
@@ -7,7 +7,7 @@ import { Order } from 'src/modules/order/entities/order.entity';
|
||||
|
||||
@Entity({ tableName: 'invoice_items' })
|
||||
export class InvoiceItem extends BaseEntity {
|
||||
[OptionalProps]?: 'createdAt' | 'deletedAt' | 'subTotal' | 'total';
|
||||
[OptionalProps]?: 'createdAt' | 'deletedAt' | 'discount' | 'description' | 'confirmedAt';
|
||||
|
||||
@ManyToOne(() => Invoice)
|
||||
invoice!: Invoice;
|
||||
@@ -22,16 +22,15 @@ export class InvoiceItem extends BaseEntity {
|
||||
@Property({ type: 'int' })
|
||||
quantity!: number;
|
||||
|
||||
@Property({ type: 'int' })
|
||||
unitPrice: number;
|
||||
@Property({ type: 'int', fieldName: 'unit_price' })
|
||||
unitPrice!: number;
|
||||
|
||||
@Property({
|
||||
type: 'int',
|
||||
// columnType: 'int GENERATED ALWAYS AS (COALESCE(unit_price, 0) * quantity) STORED',
|
||||
// persist: false,
|
||||
nullable: true
|
||||
columnType: 'int GENERATED ALWAYS AS (COALESCE(unit_price, 0) * quantity) STORED',
|
||||
persist: false,
|
||||
})
|
||||
subTotal!: number;
|
||||
subTotal!: number & Opt;
|
||||
|
||||
@Property({
|
||||
type: 'int',
|
||||
@@ -41,11 +40,10 @@ export class InvoiceItem extends BaseEntity {
|
||||
|
||||
@Property({
|
||||
type: 'int',
|
||||
nullable: true,
|
||||
// columnType: 'int GENERATED ALWAYS AS ((COALESCE(unit_price, 0) * quantity) - COALESCE(discount, 0)) STORED',
|
||||
// persist: false
|
||||
columnType: 'int GENERATED ALWAYS AS ((COALESCE(unit_price, 0) * quantity) - COALESCE(discount, 0)) STORED',
|
||||
persist: false
|
||||
})
|
||||
total!: number;
|
||||
total!: number & Opt;
|
||||
|
||||
@Property({ type: 'text', nullable: true })
|
||||
description?: string;
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
Enum,
|
||||
PrimaryKey,
|
||||
OptionalProps,
|
||||
Opt,
|
||||
} from '@mikro-orm/core';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { Payment } from 'src/modules/payment/entities/payment.entity';
|
||||
@@ -23,7 +24,7 @@ import { IAttachment } from 'src/modules/order/interface/order.interface';
|
||||
@Entity({ tableName: 'invoices' })
|
||||
@Index({ properties: ['user'] })
|
||||
export class Invoice extends BaseEntity {
|
||||
[OptionalProps]?: 'createdAt' | 'deletedAt' | 'invoiceNumber' | 'request'
|
||||
[OptionalProps]?: 'createdAt' | 'deletedAt'
|
||||
|
||||
@PrimaryKey({ type: 'string', columnType: 'char(26)' })
|
||||
id: string = ulid()
|
||||
@@ -48,34 +49,34 @@ export class Invoice extends BaseEntity {
|
||||
|
||||
|
||||
@Property({
|
||||
type: 'int',
|
||||
autoincrement: true
|
||||
type: 'int',
|
||||
unique: true
|
||||
})
|
||||
invoiceNumber: number;
|
||||
|
||||
|
||||
@Property({ type: 'int', nullable: true })
|
||||
discount?: number;
|
||||
@Property({ type: 'int' })
|
||||
discount!: number & Opt;
|
||||
|
||||
|
||||
@Property({ type: 'int', nullable: true })
|
||||
subTotal?: number;
|
||||
@Property({ type: 'int' })
|
||||
subTotal!: number & Opt;
|
||||
|
||||
|
||||
@Property({ type: 'int', nullable: true })
|
||||
taxAmount?: number;
|
||||
@Property({ type: 'int' })
|
||||
taxAmount!: number & Opt;
|
||||
|
||||
|
||||
@Property({ type: 'int', nullable: true })
|
||||
total?: number;
|
||||
@Property({ type: 'int' })
|
||||
total!: number & Opt;
|
||||
|
||||
|
||||
@Property({ type: 'int', default: 0 })
|
||||
paidAmount: number = 0;
|
||||
|
||||
|
||||
@Property({ type: 'int', default: 0 })
|
||||
balance: number = 0;
|
||||
@Property({ type: 'int' })
|
||||
balance: number & Opt;
|
||||
|
||||
|
||||
// @Enum(() => InvoiceStatusEnum)
|
||||
|
||||
@@ -61,7 +61,7 @@ export class InvoiceService {
|
||||
approvalDeadline,
|
||||
discount,
|
||||
paidAmount: 0,
|
||||
balance: 0,
|
||||
// balance: 0,
|
||||
attachments: [],
|
||||
paymentMethod: dto.paymentMethod,
|
||||
invoiceNumber: 20,
|
||||
@@ -69,14 +69,14 @@ export class InvoiceService {
|
||||
});
|
||||
em.persist(invoice);
|
||||
|
||||
let subTotal = 0;
|
||||
// let subTotal = 0;
|
||||
|
||||
for (const item of dto.items) {
|
||||
const product = await this.productService.findOneOrFail(item.productId);
|
||||
const unitPrice = item.unitPrice;
|
||||
const itemDiscount = item.discount ?? 0;
|
||||
const itemTotal = Math.max(0, unitPrice * item.quantity - itemDiscount);
|
||||
subTotal += itemTotal;
|
||||
// subTotal += itemTotal;
|
||||
|
||||
const invoiceItem = em.create(InvoiceItem, {
|
||||
invoice,
|
||||
@@ -89,16 +89,16 @@ export class InvoiceService {
|
||||
invoice.items.add(invoiceItem);
|
||||
}
|
||||
|
||||
const taxAmount = enableTax
|
||||
? Math.round((subTotal - discount) * TAX_RATE)
|
||||
: 0;
|
||||
const total = Math.max(0, subTotal - discount + taxAmount);
|
||||
// const taxAmount = enableTax
|
||||
// ? Math.round((subTotal - discount) * TAX_RATE)
|
||||
// : 0;
|
||||
// const total = Math.max(0, subTotal - discount + taxAmount);
|
||||
|
||||
invoice.subTotal = subTotal;
|
||||
// invoice.subTotal = subTotal;
|
||||
invoice.attachments = dto.attachments;
|
||||
invoice.taxAmount = taxAmount;
|
||||
invoice.total = total;
|
||||
invoice.balance = total - invoice.paidAmount;
|
||||
// invoice.taxAmount = taxAmount;
|
||||
// invoice.total = total;
|
||||
// invoice.balance = total - invoice.paidAmount;
|
||||
|
||||
if (dto.requestId) {
|
||||
const requestEntity = await em.findOne(
|
||||
|
||||
@@ -3,10 +3,9 @@ import type { OrderStatusEnum } from '../interface/order.interface';
|
||||
export class OrderCreatedEvent {
|
||||
constructor(
|
||||
public readonly orderId: string,
|
||||
public readonly: string,
|
||||
public readonly orderNumber: string,
|
||||
public readonly total: number,
|
||||
) { }
|
||||
public readonly userId: string,
|
||||
public readonly orderNumber: number,
|
||||
) {}
|
||||
}
|
||||
|
||||
export class OrderStatusChangedEvent {
|
||||
|
||||
@@ -1,212 +1,57 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { AdminRepository } from 'src/modules/admin/repositories/admin.repository';
|
||||
import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events';
|
||||
import { PermissionEnum } from 'src/common/enums/permission.enum';
|
||||
import { OrderCreatedEvent } from '../events/order.events';
|
||||
import { NotifTitle } from 'src/modules/notification/interfaces/notification.interface';
|
||||
import { NotificationService } from 'src/modules/notification/services/notification.service';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { OrderRepository } from '../repositories/order.repository';
|
||||
// import { OrderStatusEnum } from '../interface/order.interface';
|
||||
import { PaymentMethodEnum } from 'src/modules/payment/interface/payment';
|
||||
import { UserService } from 'src/modules/user/providers/user.service';
|
||||
import { NotifChannelEnum } from 'src/modules/notification/interfaces/notification.interface';
|
||||
|
||||
@Injectable()
|
||||
export class OrderListeners {
|
||||
private readonly logger = new Logger(OrderListeners.name);
|
||||
private orderCreatedSmsTemplateId: string;
|
||||
private orderStatusChangedSmsTemplateId: string;
|
||||
// private orderCompletedSmsTemplateId: string;
|
||||
|
||||
constructor(
|
||||
private readonly adminService: AdminRepository,
|
||||
private readonly OrderRepository: OrderRepository,
|
||||
private readonly notificationService: NotificationService,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly userService: UserService,
|
||||
) {
|
||||
this.orderCreatedSmsTemplateId = this.configService.get<string>('SMS_PATTERN_ORDER_CREATED') ?? '123';
|
||||
this.orderStatusChangedSmsTemplateId = this.configService.get<string>('SMS_PATTERN_ORDER_STATUS_CHANGE') ?? '123';
|
||||
// this.orderCompletedSmsTemplateId = this.configService.get<string>('SMS_PATTERN_ORDER_STATUS_COMPLETED') ?? '123';
|
||||
this.orderCreatedSmsTemplateId =
|
||||
this.configService.get<string>('SMS_PATTERN_ORDER_CREATED') ?? '';
|
||||
}
|
||||
|
||||
// private getStatusFarsi(status: OrderStatus): string {
|
||||
// const statusMap: Record<OrderStatus, string> = {
|
||||
// [OrderStatus.PENDING_PAYMENT]: 'در انتظار پرداخت',
|
||||
// [OrderStatus.PAID]: 'پرداخت شده',
|
||||
// [OrderStatus.PREPARING]: 'در حال آمادهسازی',
|
||||
// [OrderStatus.DELIVERED_TO_RECEPTIONIST]: 'تحویل به پذیرش',
|
||||
// [OrderStatus.DELIVERED_TO_WAITER]: 'تحویل به گارسون',
|
||||
// [OrderStatus.SHIPPED]: 'ارسال شده',
|
||||
// [OrderStatus.COMPLETED]: 'تکمیل شده',
|
||||
// [OrderStatus.CANCELED]: 'لغو شده',
|
||||
// };
|
||||
// return statusMap[status] || status;
|
||||
// }
|
||||
@OnEvent(OrderCreatedEvent.name)
|
||||
async handleOrderCreated(event: OrderCreatedEvent) {
|
||||
try {
|
||||
this.logger.log(
|
||||
`Order created event: orderId=${event.orderId}, orderNumber=${event.orderNumber}, userId=${event.userId}`,
|
||||
);
|
||||
|
||||
// @OnEvent(OrderCreatedEvent.name)
|
||||
// async handleOrderCreated(event: OrderCreatedEvent) {
|
||||
// try {
|
||||
// this.logger.log(
|
||||
// `Order created event received: ${event.orderId} for restaurant: ${event.} and order number: ${event.orderNumber}`,
|
||||
// );
|
||||
const body = `سفارش شماره ${event.orderNumber} با موفقیت ایجاد شد`;
|
||||
|
||||
// const order = await this.OrderRepository.findOne(event.orderId);
|
||||
// if (order?.paymentMethod.method === PaymentMethodEnum.Online) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
|
||||
// // get admnin os restuaraant that have order permissuins
|
||||
// const admins = await this.adminService.findAdminsWithPermission(event., Permission.MANAGE_ORDERS);
|
||||
// const recipients = admins.map(admin => ({
|
||||
// adminId: admin.id,
|
||||
// }));
|
||||
|
||||
// await this.notificationService.sendNotification({
|
||||
|
||||
// message: {
|
||||
// title: NotifTitleEnum.ORDER_CREATED,
|
||||
// content: `سفارش شماره ${event.orderNumber} با مبلغ ${event.total} تومان با موفقیت ایجاد شد`,
|
||||
// sms: {
|
||||
// templateId: this.orderCreatedSmsTemplateId,
|
||||
// parameters: {
|
||||
// orderNumber: event.orderNumber,
|
||||
// total: event.total.toString(),
|
||||
// },
|
||||
// },
|
||||
// pushNotif: {
|
||||
// title: `سفارش جدید`,
|
||||
// content: `سفارش شماره ${event.orderNumber} با مبلغ ${event.total} تومان با موفقیت ایجاد شد`,
|
||||
// icon: `/`,
|
||||
// action: {
|
||||
// type: NotifTitleEnum.ORDER_CREATED,
|
||||
// url: `/`,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// recipients,
|
||||
// metadata: {
|
||||
// priority: 1,
|
||||
// },
|
||||
// });
|
||||
// } catch (error) {
|
||||
// this.logger.error(
|
||||
// `Failed to send notification for order created event: ${event.}`,
|
||||
// error instanceof Error ? error.stack : String(error),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
// @OnEvent(OrderStatusChangedEvent.name)
|
||||
// async handleOrderStatusChanged(event: OrderStatusChangedEvent) {
|
||||
// try {
|
||||
// this.logger.log(
|
||||
// `Order status changed event received: ${event.orderId} for restaurant: ${event.} and order number: ${event.orderNumber}`,
|
||||
// );
|
||||
// //TODO : REFACTOR to use queue or other way to handle this
|
||||
// const recipients = [
|
||||
// {
|
||||
// userId: event.userId,
|
||||
// },
|
||||
// ];
|
||||
// if (event.newStatus === OrderStatus.COMPLETED) {
|
||||
|
||||
// if (!event?.userId) {
|
||||
// this.logger.log(
|
||||
// `User not found for order: ${event.orderId} for restaurant: ${event.} and order number: ${event.orderNumber}`,
|
||||
// );
|
||||
// }
|
||||
|
||||
// // const restaurant = await this.RestaurantRepository.findOne(event.);
|
||||
// // if (!restaurant) {
|
||||
// // this.logger.log(
|
||||
// // `Restaurant not found for order: ${event.orderId} for restaurant: ${event.} and order number: ${event.orderNumber}`,
|
||||
// // );
|
||||
// // return;
|
||||
// // }
|
||||
// // const score = restaurant.score;
|
||||
// // if (!score) {
|
||||
// // this.logger.log(
|
||||
// // `Score not found for restaurant: ${event.} and order number: ${event.orderNumber}`,
|
||||
// // );
|
||||
// // return;
|
||||
// // }
|
||||
|
||||
// // increase score for user
|
||||
// // const order = await this.OrderRepository.findOne(event.orderId);
|
||||
// // if (!order) {
|
||||
// // this.logger.log(
|
||||
// // `Order not found for order: ${event.orderId} for restaurant: ${event.} and order number: ${event.orderNumber}`,
|
||||
// // );
|
||||
// // return;
|
||||
// // }
|
||||
// // this.userService.createWalletTransaction(event.userId, event., {
|
||||
// // amount: order.subTotal,
|
||||
// // type: WalletTransactionType.CREDIT,
|
||||
// // reason: WalletTransactionReason.ORDER_COMPLETED_DEPOSIT,
|
||||
// // });
|
||||
|
||||
// await this.notificationService.sendNotification({
|
||||
// : event.,
|
||||
// message: {
|
||||
// title: NotifTitleEnum.ORDER_STATUS_CHANGED,
|
||||
// content: `لطفابرای ثبت نظر سفارش ${event.orderNumber} به اپ مراجعه کنید`,
|
||||
// sms: {
|
||||
// templateId: this.orderCreatedSmsTemplateId,
|
||||
// parameters: {
|
||||
// orderNumber: event.orderNumber,
|
||||
// },
|
||||
// },
|
||||
// pushNotif: {
|
||||
// title: `تغییر وضعیت سفارش`,
|
||||
// content: `لطفا برای ثبت نظر سفارش ${event.orderNumber} به اپ مراجعه کنید`,
|
||||
// icon: `/`,
|
||||
// action: {
|
||||
// type: NotifTitleEnum.ORDER_STATUS_CHANGED,
|
||||
// url: ``,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// recipients,
|
||||
// metadata: {
|
||||
// priority: 1,
|
||||
// },
|
||||
// });
|
||||
// } else {
|
||||
// await this.notificationService.sendNotification({
|
||||
// : event.,
|
||||
// message: {
|
||||
// title: NotifTitleEnum.ORDER_STATUS_CHANGED,
|
||||
// content: `وضعیت سفارش شماره ${event.orderNumber} به ${this.getStatusFarsi(event.newStatus)} تغییر کرد`,
|
||||
// sms: {
|
||||
// templateId: this.orderStatusChangedSmsTemplateId,
|
||||
// parameters: {
|
||||
// orderNumber: event.orderNumber,
|
||||
// status: this.getStatusFarsi(event.newStatus),
|
||||
// },
|
||||
// },
|
||||
// pushNotif: {
|
||||
// title: `تغییر وضعیت سفارش`,
|
||||
// content: `وضعیت سفارش شماره ${event.orderNumber} به ${this.getStatusFarsi(event.newStatus)} تغییر کرد`,
|
||||
// icon: `/`,
|
||||
// action: {
|
||||
// type: NotifTitleEnum.ORDER_STATUS_CHANGED,
|
||||
// url: ``,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// recipients,
|
||||
// metadata: {
|
||||
// priority: 1,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// } catch (error) {
|
||||
// this.logger.error(
|
||||
// `Failed to send notification for order status changed event: ${event.}`,
|
||||
// error instanceof Error ? error.stack : String(error),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
await this.notificationService.sendNotification({
|
||||
channels: [NotifChannelEnum.SMS],
|
||||
recipients: [{ userId: event.userId }],
|
||||
message: {
|
||||
title: NotifTitle.NEW_ORDER,
|
||||
content: body,
|
||||
sms: {
|
||||
templateId: this.orderCreatedSmsTemplateId,
|
||||
parameters: {
|
||||
orderNumber: String(event.orderNumber),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.log(
|
||||
`Notification sent to user ${event.userId} for order ${event.orderId}`,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to send notification for order created: ${event.orderId}`,
|
||||
error instanceof Error ? error.stack : String(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,30 +8,22 @@ import {
|
||||
} from '../dto/create-order.dto';
|
||||
import { UserService } from 'src/modules/user/providers/user.service';
|
||||
import { OrderStatusEnum } from '../interface/order.interface';
|
||||
import { ProductService } from 'src/modules/product/providers/product.service';
|
||||
import { ProductRepository } from 'src/modules/product/repositories/product.repository';
|
||||
import { ChattService } from 'src/modules/chat/providers/chat.service';
|
||||
import { ChatRepository } from 'src/modules/chat/repositories/chat.repository';
|
||||
import { AdminRepository } from 'src/modules/admin/repositories/admin.repository';
|
||||
import { Order } from '../entities/order.entity';
|
||||
import { PaymentRepository } from 'src/modules/payment/repositories/payment.repository';
|
||||
import { AdminService } from 'src/modules/admin/providers/admin.service';
|
||||
import { UpdateOrderAsAdminDto } from '../dto/update-order.dto';
|
||||
import { FindOrderItemsDto } from '../dto/find-order-items.dto';
|
||||
import { PermissionService } from 'src/modules/roles/providers/permissions.service';
|
||||
import { PermissionEnum } from 'src/common/enums/permission.enum';
|
||||
import { User } from 'src/modules/user/entities/user.entity';
|
||||
import { Product } from 'src/modules/product/entities/product.entity';
|
||||
import { Category } from 'src/modules/product/entities/category.entity';
|
||||
import { InvoiceItem } from 'src/modules/invoice/entities/invoice-item.entity';
|
||||
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
||||
import { UpdateStatusAsDesignerDto } from '../dto/update-status-as-designer.dto';
|
||||
import { UpdateStatusDto } from '../dto/update-status.dto';
|
||||
import { CreateOrderPrintDto } from '../dto/create-order-print.dto';
|
||||
import { OrderPrint } from '../entities/print.entity';
|
||||
import { OrderPrintRepository } from '../repositories/order-print.repository';
|
||||
import { Request } from 'src/modules/request/entities/request.entity';
|
||||
import { Invoice } from 'src/modules/invoice/entities/invoice.entity';
|
||||
import { OrderCreatedEvent } from '../events/order.events';
|
||||
|
||||
@Injectable()
|
||||
export class OrderService {
|
||||
@@ -43,7 +35,8 @@ export class OrderService {
|
||||
private readonly userService: UserService,
|
||||
private readonly adminService: AdminService,
|
||||
private readonly orderPrintRepository: OrderPrintRepository,
|
||||
) { }
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) {}
|
||||
|
||||
async createOrderAsAdmin(adminId: string, dto: CreateOrderAsAdminDto): Promise<Order> {
|
||||
let invoiceItem: null | InvoiceItem = null
|
||||
@@ -104,6 +97,12 @@ export class OrderService {
|
||||
});
|
||||
|
||||
await this.em.persistAndFlush(order);
|
||||
|
||||
this.eventEmitter.emit(
|
||||
OrderCreatedEvent.name,
|
||||
new OrderCreatedEvent(order.id, user.id, order.orderNumber),
|
||||
);
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,4 +66,6 @@ export class TicketListeners {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add notification to user when ticket message is created by admin
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user