task-e
This commit is contained in:
146
src/db/schema.ts
146
src/db/schema.ts
@@ -246,3 +246,149 @@ export const crmEnquiryFollowups = pgTable('crm_enquiry_followups', {
|
||||
createdBy: text('created_by').notNull(),
|
||||
updatedBy: text('updated_by').notNull()
|
||||
});
|
||||
|
||||
export const crmQuotations = pgTable(
|
||||
'crm_quotations',
|
||||
{
|
||||
id: text('id').primaryKey(),
|
||||
organizationId: text('organization_id').notNull(),
|
||||
branchId: text('branch_id'),
|
||||
code: text('code').notNull(),
|
||||
enquiryId: text('enquiry_id'),
|
||||
customerId: text('customer_id').notNull(),
|
||||
contactId: text('contact_id'),
|
||||
quotationDate: timestamp('quotation_date', { withTimezone: true }).notNull(),
|
||||
validUntil: timestamp('valid_until', { withTimezone: true }),
|
||||
quotationType: text('quotation_type').notNull(),
|
||||
projectName: text('project_name'),
|
||||
projectLocation: text('project_location'),
|
||||
attention: text('attention'),
|
||||
reference: text('reference'),
|
||||
notes: text('notes'),
|
||||
status: text('status').notNull(),
|
||||
revision: integer('revision').default(0).notNull(),
|
||||
parentQuotationId: text('parent_quotation_id'),
|
||||
revisionRemark: text('revision_remark'),
|
||||
currency: text('currency').notNull(),
|
||||
exchangeRate: doublePrecision('exchange_rate').default(1).notNull(),
|
||||
subtotal: doublePrecision('subtotal').default(0).notNull(),
|
||||
discount: doublePrecision('discount').default(0).notNull(),
|
||||
discountType: text('discount_type'),
|
||||
taxRate: doublePrecision('tax_rate').default(0).notNull(),
|
||||
taxAmount: doublePrecision('tax_amount').default(0).notNull(),
|
||||
totalAmount: doublePrecision('total_amount').default(0).notNull(),
|
||||
chancePercent: integer('chance_percent'),
|
||||
isHotProject: boolean('is_hot_project').default(false).notNull(),
|
||||
competitor: text('competitor'),
|
||||
salesmanId: text('salesman_id'),
|
||||
isSent: boolean('is_sent').default(false).notNull(),
|
||||
sentAt: timestamp('sent_at', { withTimezone: true }),
|
||||
sentVia: text('sent_via'),
|
||||
acceptedAt: timestamp('accepted_at', { withTimezone: true }),
|
||||
rejectedAt: timestamp('rejected_at', { withTimezone: true }),
|
||||
rejectionReason: text('rejection_reason'),
|
||||
isActive: boolean('is_active').default(true).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
deletedAt: timestamp('deleted_at', { withTimezone: true }),
|
||||
createdBy: text('created_by').notNull(),
|
||||
updatedBy: text('updated_by').notNull()
|
||||
},
|
||||
(table) => ({
|
||||
organizationCodeIdx: uniqueIndex('crm_quotations_org_code_idx').on(
|
||||
table.organizationId,
|
||||
table.code
|
||||
)
|
||||
})
|
||||
);
|
||||
|
||||
export const crmQuotationItems = pgTable('crm_quotation_items', {
|
||||
id: text('id').primaryKey(),
|
||||
organizationId: text('organization_id').notNull(),
|
||||
quotationId: text('quotation_id').notNull(),
|
||||
itemNumber: integer('item_number').notNull(),
|
||||
productType: text('product_type').notNull(),
|
||||
description: text('description').notNull(),
|
||||
quantity: doublePrecision('quantity').default(0).notNull(),
|
||||
unit: text('unit'),
|
||||
unitPrice: doublePrecision('unit_price').default(0).notNull(),
|
||||
discount: doublePrecision('discount').default(0).notNull(),
|
||||
discountType: text('discount_type'),
|
||||
taxRate: doublePrecision('tax_rate').default(0).notNull(),
|
||||
totalPrice: doublePrecision('total_price').default(0).notNull(),
|
||||
notes: text('notes'),
|
||||
sortOrder: integer('sort_order').default(0).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
deletedAt: timestamp('deleted_at', { withTimezone: true })
|
||||
});
|
||||
|
||||
export const crmQuotationCustomers = pgTable('crm_quotation_customers', {
|
||||
id: text('id').primaryKey(),
|
||||
organizationId: text('organization_id').notNull(),
|
||||
quotationId: text('quotation_id').notNull(),
|
||||
customerId: text('customer_id').notNull(),
|
||||
role: text('role').notNull(),
|
||||
isPrimary: boolean('is_primary').default(false).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
deletedAt: timestamp('deleted_at', { withTimezone: true })
|
||||
});
|
||||
|
||||
export const crmQuotationTopics = pgTable('crm_quotation_topics', {
|
||||
id: text('id').primaryKey(),
|
||||
organizationId: text('organization_id').notNull(),
|
||||
quotationId: text('quotation_id').notNull(),
|
||||
topicType: text('topic_type').notNull(),
|
||||
title: text('title').notNull(),
|
||||
sortOrder: integer('sort_order').default(0).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
deletedAt: timestamp('deleted_at', { withTimezone: true })
|
||||
});
|
||||
|
||||
export const crmQuotationTopicItems = pgTable('crm_quotation_topic_items', {
|
||||
id: text('id').primaryKey(),
|
||||
organizationId: text('organization_id').notNull(),
|
||||
topicId: text('topic_id').notNull(),
|
||||
content: text('content').notNull(),
|
||||
sortOrder: integer('sort_order').default(0).notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
deletedAt: timestamp('deleted_at', { withTimezone: true })
|
||||
});
|
||||
|
||||
export const crmQuotationFollowups = pgTable('crm_quotation_followups', {
|
||||
id: text('id').primaryKey(),
|
||||
organizationId: text('organization_id').notNull(),
|
||||
quotationId: text('quotation_id').notNull(),
|
||||
followupDate: timestamp('followup_date', { withTimezone: true }).notNull(),
|
||||
followupType: text('followup_type').notNull(),
|
||||
contactId: text('contact_id'),
|
||||
outcome: text('outcome'),
|
||||
notes: text('notes'),
|
||||
nextFollowupDate: timestamp('next_followup_date', { withTimezone: true }),
|
||||
nextAction: text('next_action'),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
deletedAt: timestamp('deleted_at', { withTimezone: true }),
|
||||
createdBy: text('created_by').notNull(),
|
||||
updatedBy: text('updated_by').notNull()
|
||||
});
|
||||
|
||||
export const crmQuotationAttachments = pgTable('crm_quotation_attachments', {
|
||||
id: text('id').primaryKey(),
|
||||
organizationId: text('organization_id').notNull(),
|
||||
quotationId: text('quotation_id').notNull(),
|
||||
fileName: text('file_name').notNull(),
|
||||
originalFileName: text('original_file_name').notNull(),
|
||||
filePath: text('file_path').notNull(),
|
||||
fileSize: integer('file_size'),
|
||||
fileType: text('file_type'),
|
||||
description: text('description'),
|
||||
uploadedAt: timestamp('uploaded_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
uploadedBy: text('uploaded_by').notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
deletedAt: timestamp('deleted_at', { withTimezone: true })
|
||||
});
|
||||
|
||||
@@ -121,6 +121,11 @@ const FOUNDATION_OPTIONS = {
|
||||
{ code: 'cancelled', label: 'Cancelled', value: 'cancelled', sortOrder: 8 },
|
||||
{ code: 'revised', label: 'Revised', value: 'revised', sortOrder: 9 }
|
||||
],
|
||||
crm_quotation_type: [
|
||||
{ code: 'standard', label: 'Standard', value: 'standard', sortOrder: 1 },
|
||||
{ code: 'budgetary', label: 'Budgetary', value: 'budgetary', sortOrder: 2 },
|
||||
{ code: 'service', label: 'Service', value: 'service', sortOrder: 3 }
|
||||
],
|
||||
crm_product_type: [
|
||||
{ code: 'crane', label: 'Crane', value: 'crane', sortOrder: 1 },
|
||||
{ code: 'dockdoor', label: 'Dock Door', value: 'dockdoor', sortOrder: 2 },
|
||||
@@ -131,6 +136,15 @@ const FOUNDATION_OPTIONS = {
|
||||
{ code: 'USD', label: 'USD', value: 'USD', sortOrder: 2 },
|
||||
{ code: 'EUR', label: 'EUR', value: 'EUR', sortOrder: 3 }
|
||||
],
|
||||
crm_discount_type: [
|
||||
{ code: 'amount', label: 'Amount', value: 'amount', sortOrder: 1 },
|
||||
{ code: 'percent', label: 'Percent', value: 'percent', sortOrder: 2 }
|
||||
],
|
||||
crm_topic_type: [
|
||||
{ code: 'scope', label: 'Scope', value: 'scope', sortOrder: 1 },
|
||||
{ code: 'exclusion', label: 'Exclusion', value: 'exclusion', sortOrder: 2 },
|
||||
{ code: 'payment', label: 'Payment', value: 'payment', sortOrder: 3 }
|
||||
],
|
||||
crm_payment_term: [
|
||||
{ code: 'cash', label: 'Cash', value: 'cash', sortOrder: 1 },
|
||||
{ code: 'credit_30', label: 'Credit 30', value: 'credit_30', sortOrder: 2 },
|
||||
|
||||
Reference in New Issue
Block a user