Spaces:
Running
Running
File size: 41,335 Bytes
69f2a47 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 | -- ============================================================================
-- Database Schema for SCM Microservice
-- Includes: Trans Schema, SCM Tables, and Sales Order Tables
-- ============================================================================
-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Create Role if not exists
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'trans_owner') THEN
CREATE ROLE trans_owner WITH LOGIN PASSWORD 'trans_password'; -- Set a default password or leave it nologin
END IF;
END
$$;
-- Create Schema
CREATE SCHEMA IF NOT EXISTS trans;
ALTER SCHEMA trans OWNER TO trans_owner;
-- ============================================================================
-- Core Reference Tables
-- ============================================================================
-- Catalogue Reference
CREATE TABLE IF NOT EXISTS trans.catalogue_ref (
catalogue_id TEXT PRIMARY KEY,
catalogue_code TEXT,
catalogue_type TEXT NOT NULL,
catalogue_name TEXT NOT NULL,
sku TEXT,
barcode_number TEXT,
hsn_code TEXT,
gst_rate NUMERIC(5,2),
mrp NUMERIC(12,2),
base_price NUMERIC(12,2),
track_inventory BOOLEAN DEFAULT FALSE,
batch_managed BOOLEAN DEFAULT FALSE,
status TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
merchant_id TEXT[],
pricing_levels JSON
);
CREATE INDEX IF NOT EXISTS idx_catalogue_ref_catalogue_code ON trans.catalogue_ref (catalogue_code);
CREATE INDEX IF NOT EXISTS idx_catalogue_ref_catalogue_type ON trans.catalogue_ref (catalogue_type);
CREATE INDEX IF NOT EXISTS idx_catalogue_ref_sku ON trans.catalogue_ref (sku);
CREATE INDEX IF NOT EXISTS idx_catalogue_ref_status ON trans.catalogue_ref (status);
CREATE INDEX IF NOT EXISTS idx_catalogue_ref_pricing_levels_currency ON trans.catalogue_ref USING GIN ((pricing_levels->>'currency'));
-- UOM Groups
CREATE TABLE IF NOT EXISTS trans.scm_uom_group_ref (
uom_group_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
uom_group_code VARCHAR(50) UNIQUE,
name VARCHAR(100) NOT NULL,
base_unit VARCHAR(50) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'inactive')),
units JSON NOT NULL DEFAULT '[]',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_uom_group_code ON trans.scm_uom_group_ref (uom_group_code);
CREATE INDEX IF NOT EXISTS idx_uom_group_name ON trans.scm_uom_group_ref (name);
-- Stored Objects (Documents)
CREATE TABLE IF NOT EXISTS trans.stored_objects (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
tenant_id TEXT NOT NULL,
domain TEXT NOT NULL,
entity_id TEXT NOT NULL,
bucket_name TEXT NOT NULL,
object_key TEXT NOT NULL,
category TEXT NOT NULL,
file_name TEXT NOT NULL,
mime_type TEXT NOT NULL,
file_size BIGINT,
checksum_sha256 TEXT,
visibility VARCHAR(16) NOT NULL DEFAULT 'private',
created_by TEXT NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
legal_hold BOOLEAN NOT NULL DEFAULT FALSE,
CONSTRAINT uq_stored_object_active_key UNIQUE (tenant_id, domain, entity_id, object_key, deleted_at)
);
CREATE INDEX IF NOT EXISTS ix_stored_objects_active ON trans.stored_objects (tenant_id, domain, entity_id) WHERE deleted_at IS NULL;
CREATE INDEX IF NOT EXISTS ix_stored_objects_checksum ON trans.stored_objects (tenant_id, checksum_sha256) WHERE deleted_at IS NULL;
-- ============================================================================
-- SCM Purchase Orders
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_po (
po_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
po_no VARCHAR(50) UNIQUE NOT NULL,
buyer_id UUID NOT NULL,
buyer_type VARCHAR(20) NOT NULL,
supplier_id UUID NOT NULL,
supplier_type VARCHAR(20) NOT NULL,
po_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
exp_delivery_dt DATE,
currency VARCHAR(3) NOT NULL DEFAULT 'INR',
total_amt NUMERIC(14, 2) NOT NULL,
tax_amt NUMERIC(14, 2) DEFAULT 0,
net_amt NUMERIC(14, 2) NOT NULL,
status VARCHAR(20) NOT NULL,
remarks TEXT,
created_by VARCHAR(64) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.scm_po_item (
po_item_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
po_id UUID NOT NULL REFERENCES trans.scm_po(po_id) ON DELETE CASCADE,
catalogue_id UUID NOT NULL,
sku VARCHAR(64) NOT NULL,
batch_managed BOOLEAN,
ord_qty NUMERIC(12, 3) NOT NULL,
ord_uom_qty NUMERIC(12, 3) NOT NULL,
rcvd_qty NUMERIC(12, 3) DEFAULT 0,
invoiced_qty NUMERIC(12, 3) DEFAULT 0,
returned_qty NUMERIC(12, 3) DEFAULT 0,
dispatched_qty NUMERIC(12, 3) DEFAULT 0,
rejected_qty NUMERIC(12, 3) DEFAULT 0,
uom VARCHAR(10) NOT NULL,
ord_uom VARCHAR(10) NOT NULL,
unit_price NUMERIC(12, 2) NOT NULL,
line_amt NUMERIC(14, 2) NOT NULL,
tax_rate NUMERIC(5, 2) DEFAULT 0,
tax_amt NUMERIC(12, 2) DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.scm_po_status_log (
log_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
po_id UUID NOT NULL REFERENCES trans.scm_po(po_id),
status VARCHAR(20) NOT NULL,
changed_by VARCHAR(64),
changed_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
remarks TEXT
);
-- ============================================================================
-- SCM PO Returns
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_po_return (
po_return_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
po_return_no VARCHAR(40) UNIQUE NOT NULL,
po_id UUID NOT NULL,
supplier_id VARCHAR(64) NOT NULL,
client_id VARCHAR(64) NOT NULL,
warehouse_id VARCHAR(64),
return_date TIMESTAMP NOT NULL,
status VARCHAR(20) NOT NULL,
reason_code VARCHAR(50),
remarks TEXT,
created_by VARCHAR(64),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_po_return_po_id ON trans.scm_po_return(po_id);
CREATE INDEX IF NOT EXISTS idx_po_return_supplier_id ON trans.scm_po_return(supplier_id);
CREATE INDEX IF NOT EXISTS idx_po_return_client_id ON trans.scm_po_return(client_id);
CREATE TABLE IF NOT EXISTS trans.scm_po_return_item (
po_return_item_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
po_return_id UUID NOT NULL REFERENCES trans.scm_po_return(po_return_id) ON DELETE CASCADE,
po_item_id UUID NOT NULL,
catalogue_id UUID NOT NULL,
batch_no VARCHAR(50) NOT NULL,
expiry_date TIMESTAMP,
return_qty NUMERIC(12, 3) NOT NULL,
uom VARCHAR(20) NOT NULL DEFAULT 'PCS',
cost_price NUMERIC(12, 2) NOT NULL,
return_value NUMERIC(14, 2) GENERATED ALWAYS AS (return_qty * cost_price) STORED,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_po_return_item_po_item_id ON trans.scm_po_return_item(po_item_id);
-- ============================================================================
-- SCM Goods Receipt Notes (GRN)
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_grn (
grn_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
grn_no VARCHAR(50) UNIQUE NOT NULL,
po_id UUID REFERENCES trans.scm_po(po_id),
shipment_id UUID,
receiver_id VARCHAR(64),
supplier_id UUID NOT NULL,
received_by VARCHAR(64),
transporter VARCHAR(64),
recv_dt TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
wh_location VARCHAR(64),
status VARCHAR(20) NOT NULL,
total_qty NUMERIC(14, 3),
remarks TEXT,
created_by VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.scm_grn_item (
grn_item_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
grn_id UUID NOT NULL REFERENCES trans.scm_grn(grn_id) ON DELETE CASCADE,
po_item_id UUID REFERENCES trans.scm_po_item(po_item_id),
catalogue_id UUID,
sku VARCHAR(64) NOT NULL,
recv_qty NUMERIC(12, 3) NOT NULL,
acc_qty NUMERIC(12, 3) NOT NULL,
rej_qty NUMERIC(12, 3) DEFAULT 0,
uom VARCHAR(10) NOT NULL,
batch_no VARCHAR(50),
mfg_dt DATE,
exp_dt DATE,
qc_status VARCHAR(20) DEFAULT 'accepted',
remarks TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.scm_grn_issue (
issue_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
grn_item_id UUID NOT NULL REFERENCES trans.scm_grn_item(grn_item_id),
issue_type VARCHAR(50) NOT NULL,
description TEXT,
status VARCHAR(20) NOT NULL,
created_by VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================================
-- SCM Inventory / Stock
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_stock_ledger (
ledger_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
merchant_id VARCHAR(64) NOT NULL,
warehouse_id VARCHAR(64) NOT NULL,
catalogue_id VARCHAR(64),
sku VARCHAR(64) NOT NULL,
batch_no VARCHAR(50),
txn_type VARCHAR(20) NOT NULL,
qty NUMERIC(12, 3) NOT NULL,
uom VARCHAR(20),
ref_type VARCHAR(20) NOT NULL,
ref_id UUID NOT NULL,
ref_no VARCHAR(50),
remarks TEXT,
created_by VARCHAR(64) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.scm_stock (
stock_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
merchant_id VARCHAR(64) NOT NULL,
warehouse_id VARCHAR(64) NOT NULL,
sku VARCHAR(64) NOT NULL,
batch_no VARCHAR(50),
catalogue_id VARCHAR(64),
uom VARCHAR(20) DEFAULT 'PCS',
qty_on_hand NUMERIC(12, 3) DEFAULT 0 CHECK (qty_on_hand >= 0),
qty_reserved NUMERIC(12, 3) DEFAULT 0 CHECK (qty_reserved >= 0),
qty_available NUMERIC(12, 3) DEFAULT 0 CHECK (qty_available >= 0),
cost_price NUMERIC(12, 2),
expiry_date DATE,
ledger_id UUID,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT uq_scm_stock_sku_batch UNIQUE (merchant_id, warehouse_id, catalogue_id, batch_no)
);
-- Stock Adjustment (Master/Detail)
CREATE TABLE IF NOT EXISTS trans.scm_stock_adjustment_master (
adjustment_master_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
adjustment_number VARCHAR(50) NOT NULL,
merchant_id VARCHAR(64) NOT NULL,
warehouse_id VARCHAR(64) NOT NULL,
adjustment_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
description TEXT,
additional_notes TEXT,
status VARCHAR(20) NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'pending', 'approved', 'rejected', 'applied', 'cancelled')),
total_items INTEGER DEFAULT 0,
total_adjustment_value NUMERIC(15, 2) DEFAULT 0,
requires_approval BOOLEAN DEFAULT TRUE,
approval_threshold NUMERIC(15, 2),
created_by VARCHAR(64) NOT NULL,
approved_by VARCHAR(64),
rejected_by VARCHAR(64),
applied_by VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
approved_at TIMESTAMP WITH TIME ZONE,
rejected_at TIMESTAMP WITH TIME ZONE,
applied_at TIMESTAMP WITH TIME ZONE,
rejection_reason TEXT
);
CREATE TABLE IF NOT EXISTS trans.scm_stock_adjustment_details (
adjustment_detail_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
adjustment_master_id UUID NOT NULL REFERENCES trans.scm_stock_adjustment_master(adjustment_master_id),
sku VARCHAR(64) NOT NULL,
batch_no VARCHAR(50),
adj_type VARCHAR(20) NOT NULL CHECK (adj_type IN ('damage', 'expired', 'shrinkage', 'cycle_count')),
qty NUMERIC(12, 3) NOT NULL CHECK (qty > 0),
system_qty NUMERIC(12, 3) NOT NULL DEFAULT 0 CHECK (system_qty >= 0),
direction VARCHAR(10) NOT NULL DEFAULT 'OUT' CHECK (direction IN ('IN', 'OUT')),
reason TEXT NOT NULL,
unit_cost NUMERIC(12, 4),
adjustment_value NUMERIC(15, 2),
line_status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (line_status IN ('pending', 'approved', 'rejected', 'applied')),
ledger_id UUID,
remarks TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- Stock Take (Master/Detail)
CREATE TABLE IF NOT EXISTS trans.scm_stock_take_master (
stock_take_master_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
stock_take_number VARCHAR(50) NOT NULL,
merchant_id VARCHAR(64) NOT NULL,
warehouse_id VARCHAR(64) NOT NULL,
stock_take_date TIMESTAMP WITH TIME ZONE NOT NULL,
description TEXT,
additional_notes TEXT,
status VARCHAR(20) NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'in_progress', 'completed', 'submitted', 'approved', 'rejected', 'cancelled')),
total_items INTEGER DEFAULT 0,
total_variance_value NUMERIC(15, 2) DEFAULT 0,
created_by VARCHAR(64) NOT NULL,
approved_by VARCHAR(64),
rejected_by VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
approved_at TIMESTAMP WITH TIME ZONE,
rejected_at TIMESTAMP WITH TIME ZONE,
rejection_reason TEXT
);
CREATE TABLE IF NOT EXISTS trans.scm_stock_take_details (
stock_take_detail_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
stock_take_master_id UUID NOT NULL REFERENCES trans.scm_stock_take_master(stock_take_master_id),
sku VARCHAR(64) NOT NULL,
batch_no VARCHAR(50),
system_qty NUMERIC(12, 3) NOT NULL CHECK (system_qty >= 0),
physical_qty NUMERIC(12, 3) NOT NULL CHECK (physical_qty >= 0),
variance_qty NUMERIC(12, 3) NOT NULL,
unit_cost NUMERIC(12, 4),
variance_value NUMERIC(15, 2),
line_status VARCHAR(20) NOT NULL DEFAULT 'counted' CHECK (line_status IN ('counted', 'verified', 'adjusted')),
adjustment_id UUID,
remarks TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.scm_stock_take_status_log (
log_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
stock_take_master_id UUID NOT NULL REFERENCES trans.scm_stock_take_master(stock_take_master_id) ON DELETE CASCADE,
status VARCHAR(50) NOT NULL,
changed_by VARCHAR(255),
changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
remarks TEXT
);
-- ============================================================================
-- Trade Relationships
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_trade_relationship (
relationship_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
from_merchant_id UUID NOT NULL,
to_merchant_id UUID NOT NULL,
relationship_type VARCHAR(30) NOT NULL DEFAULT 'procurement',
status VARCHAR(20) NOT NULL DEFAULT 'draft',
valid_from DATE NOT NULL DEFAULT CURRENT_DATE,
valid_to DATE,
credit_allowed BOOLEAN DEFAULT FALSE,
credit_limit NUMERIC(14, 2),
payment_terms VARCHAR(50),
price_list_id VARCHAR(50),
allowed_regions TEXT[],
allowed_categories TEXT[],
created_by VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT chk_different_merchants CHECK (from_merchant_id != to_merchant_id),
CONSTRAINT chk_validity_range CHECK (valid_to IS NULL OR valid_to >= valid_from),
CONSTRAINT chk_credit_configuration CHECK (credit_allowed = false OR (credit_allowed = true AND credit_limit IS NOT NULL AND credit_limit > 0))
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_unique_relationship ON trans.scm_trade_relationship (from_merchant_id, to_merchant_id);
CREATE INDEX IF NOT EXISTS idx_trade_from_merchant ON trans.scm_trade_relationship (from_merchant_id);
CREATE INDEX IF NOT EXISTS idx_trade_to_merchant ON trans.scm_trade_relationship (to_merchant_id);
-- ============================================================================
-- Trade Schemes
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.trade_schemes (
scheme_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
scheme_code VARCHAR(50) UNIQUE NOT NULL,
scheme_name VARCHAR(200) NOT NULL,
description TEXT,
scheme_type VARCHAR(20) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT',
applicable_level VARCHAR(20) NOT NULL,
merchant_id UUID,
valid_from DATE NOT NULL,
valid_to DATE NOT NULL,
settlement_type VARCHAR(20) NOT NULL,
settlement_frequency VARCHAR(20) NOT NULL,
inherit_to_children BOOLEAN DEFAULT TRUE,
allow_child_override BOOLEAN DEFAULT TRUE,
allow_better_only BOOLEAN DEFAULT TRUE,
currency VARCHAR(3) DEFAULT 'INR',
created_by VARCHAR(100),
approved_by VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
approved_at TIMESTAMP,
version INTEGER DEFAULT 1
);
CREATE INDEX IF NOT EXISTS idx_trade_schemes_type_status ON trans.trade_schemes (scheme_type, status);
CREATE INDEX IF NOT EXISTS idx_trade_schemes_validity ON trans.trade_schemes (valid_from, valid_to);
CREATE TABLE IF NOT EXISTS trans.trade_scheme_conditions (
condition_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
scheme_id UUID NOT NULL REFERENCES trans.trade_schemes(scheme_id),
min_quantity NUMERIC(15, 3),
max_quantity NUMERIC(15, 3),
qualifying_sku VARCHAR(50),
min_order_value NUMERIC(15, 2),
max_order_value NUMERIC(15, 2),
sku_list JSON,
category_list JSON,
brand_list JSON,
excluded_skus JSON,
excluded_categories JSON,
channel VARCHAR(20),
aggregate_basis VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.trade_scheme_benefits (
benefit_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
scheme_id UUID NOT NULL REFERENCES trans.trade_schemes(scheme_id),
discount_type VARCHAR(20),
discount_percentage NUMERIC(5, 2),
discount_amount NUMERIC(15, 2),
free_sku VARCHAR(50),
free_quantity NUMERIC(15, 3),
rebate_type VARCHAR(20),
rebate_percentage NUMERIC(5, 2),
rebate_amount NUMERIC(15, 2),
apply_on VARCHAR(20) DEFAULT 'TOTAL',
max_benefit_amount NUMERIC(15, 2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.trade_scheme_accruals (
accrual_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
scheme_id UUID NOT NULL REFERENCES trans.trade_schemes(scheme_id),
merchant_id UUID NOT NULL,
invoice_id VARCHAR(50),
invoice_date DATE,
accrual_amount NUMERIC(15, 2) NOT NULL,
currency VARCHAR(3) DEFAULT 'INR',
settlement_period VARCHAR(20),
status VARCHAR(20) DEFAULT 'PENDING',
credit_note_id VARCHAR(50),
settled_at TIMESTAMP,
settled_amount NUMERIC(15, 2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_accruals_scheme_merchant ON trans.trade_scheme_accruals (scheme_id, merchant_id);
CREATE TABLE IF NOT EXISTS trans.trade_scheme_applications (
application_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
scheme_id UUID NOT NULL REFERENCES trans.trade_schemes(scheme_id),
merchant_id UUID NOT NULL,
invoice_id UUID NOT NULL,
applied_amount NUMERIC(15, 2) NOT NULL,
benefit_type VARCHAR(20),
status VARCHAR(20) DEFAULT 'APPLIED',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_applications_invoice ON trans.trade_scheme_applications (invoice_id);
-- ============================================================================
-- Trade Shipment (Sales)
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_trade_shipment (
shipment_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
shipment_no VARCHAR(40) UNIQUE NOT NULL,
order_id UUID NOT NULL REFERENCES trans.scm_po(po_id),
supplier_id UUID NOT NULL,
client_id UUID NOT NULL,
warehouse_id UUID NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'shipped', 'closed')),
shipment_date DATE NOT NULL,
transporter VARCHAR(100),
lr_no VARCHAR(50),
vehicle_no VARCHAR(20),
created_by VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
total_amt NUMERIC(14, 2) NOT NULL DEFAULT 0.00,
tax_amt NUMERIC(14, 2) NOT NULL DEFAULT 0.00,
net_amt NUMERIC(14, 2) NOT NULL DEFAULT 0.00
);
CREATE INDEX IF NOT EXISTS idx_trade_shipment_order_id ON trans.scm_trade_shipment(order_id);
CREATE INDEX IF NOT EXISTS idx_trade_shipment_supplier_id ON trans.scm_trade_shipment(supplier_id);
CREATE INDEX IF NOT EXISTS idx_trade_shipment_client_id ON trans.scm_trade_shipment(client_id);
CREATE INDEX IF NOT EXISTS idx_trade_shipment_date ON trans.scm_trade_shipment(shipment_date);
CREATE INDEX IF NOT EXISTS idx_trade_shipment_status ON trans.scm_trade_shipment(status);
CREATE TABLE IF NOT EXISTS trans.scm_trade_shipment_item (
item_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
shipment_id UUID NOT NULL REFERENCES trans.scm_trade_shipment(shipment_id) ON DELETE CASCADE,
po_item_id UUID NOT NULL REFERENCES trans.scm_po_item(po_item_id),
sku VARCHAR(64) NOT NULL,
batch_no VARCHAR(50),
ordered_qty NUMERIC(12,3) NOT NULL,
shipped_qty NUMERIC(12,3) NOT NULL,
balance_qty NUMERIC(12,3) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
catalogue_id UUID,
exp_dt DATE,
unit_price NUMERIC(14, 2) NOT NULL,
line_amt NUMERIC(14, 2) NOT NULL,
tax_amt NUMERIC(14, 2),
tax_rate NUMERIC(5, 2),
CONSTRAINT chk_trade_shipment_item_qty CHECK (
shipped_qty >= 0 AND
ordered_qty >= 0 AND
balance_qty >= 0 AND
shipped_qty <= ordered_qty
)
);
CREATE INDEX IF NOT EXISTS idx_trade_shipment_item_shipment_id ON trans.scm_trade_shipment_item(shipment_id);
CREATE INDEX IF NOT EXISTS idx_trade_shipment_item_po_item_id ON trans.scm_trade_shipment_item(po_item_id);
CREATE INDEX IF NOT EXISTS idx_trade_shipment_item_sku ON trans.scm_trade_shipment_item(sku);
-- ============================================================================
-- Trade Invoices
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_invoice (
invoice_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
invoice_no VARCHAR(50) UNIQUE NOT NULL,
po_id UUID NOT NULL,
supplier_id UUID NOT NULL,
buyer_id UUID NOT NULL,
invoice_date DATE NOT NULL,
payment_terms VARCHAR(30),
due_date DATE,
currency VARCHAR(3) NOT NULL DEFAULT 'INR',
subtotal_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
discount_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
taxable_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
cgst_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
sgst_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
igst_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
total_tax_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
grand_total_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
status VARCHAR(30) NOT NULL DEFAULT 'draft',
reverse_charge BOOLEAN NOT NULL DEFAULT FALSE,
remarks TEXT,
freight_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
packing_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
other_charges_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
round_off_amt NUMERIC(14, 2) NOT NULL DEFAULT 0,
created_by VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_scm_invoice_supplier_id ON trans.scm_invoice(supplier_id);
CREATE INDEX IF NOT EXISTS idx_scm_invoice_buyer_id ON trans.scm_invoice(buyer_id);
CREATE INDEX IF NOT EXISTS idx_scm_invoice_po_id ON trans.scm_invoice(po_id);
CREATE INDEX IF NOT EXISTS idx_scm_invoice_status ON trans.scm_invoice(status);
CREATE INDEX IF NOT EXISTS idx_scm_invoice_date ON trans.scm_invoice(invoice_date);
CREATE TABLE IF NOT EXISTS trans.scm_invoice_item (
invoice_item_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
invoice_id UUID NOT NULL REFERENCES trans.scm_invoice(invoice_id) ON DELETE CASCADE,
po_item_id UUID NOT NULL,
catalogue_id UUID NOT NULL,
sku VARCHAR(64) NOT NULL,
hsn_code VARCHAR(10),
invoice_qty NUMERIC(12, 3) NOT NULL,
unit_price NUMERIC(12, 2) NOT NULL,
discount_pct NUMERIC(5, 2),
discount_amt NUMERIC(12, 2),
tax_rate NUMERIC(5, 2),
tax_amt NUMERIC(12, 2),
line_total NUMERIC(14, 2) NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_scm_invoice_item_invoice_id ON trans.scm_invoice_item(invoice_id);
CREATE INDEX IF NOT EXISTS idx_scm_invoice_item_po_item_id ON trans.scm_invoice_item(po_item_id);
CREATE TABLE IF NOT EXISTS trans.scm_invoice_status_log (
log_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
invoice_id UUID NOT NULL REFERENCES trans.scm_invoice(invoice_id) ON DELETE CASCADE,
action VARCHAR(20),
from_status VARCHAR(20),
to_status VARCHAR(20),
remarks TEXT,
performed_by VARCHAR(64),
performed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================================
-- Credit/Debit Notes (Invoice Adjustments)
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_invoice_adjustment_note (
note_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
note_no VARCHAR(50) UNIQUE NOT NULL,
invoice_id UUID NOT NULL,
supplier_id UUID NOT NULL,
buyer_id UUID NOT NULL,
category_code VARCHAR(30) NOT NULL,
reason_code VARCHAR(50) NOT NULL,
note_type VARCHAR(10) NOT NULL,
note_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
original_amount NUMERIC(14, 2),
revised_amount NUMERIC(14, 2),
adjustment_amount NUMERIC(14, 2),
taxable_amount NUMERIC(14, 2),
original_tax_rate NUMERIC(5, 2),
correct_tax_rate NUMERIC(5, 2),
tax_adjustment_amt NUMERIC(14, 2),
description TEXT NOT NULL,
remarks TEXT,
status VARCHAR(20) NOT NULL DEFAULT 'draft',
created_by VARCHAR(64),
created_by_username VARCHAR(64),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_by VARCHAR(64),
updated_by_username VARCHAR(64),
submitted_by VARCHAR(64),
submitted_at TIMESTAMP WITH TIME ZONE,
approved_by VARCHAR(64),
approved_at TIMESTAMP WITH TIME ZONE,
rejected_by VARCHAR(64),
rejected_at TIMESTAMP WITH TIME ZONE,
applied_by VARCHAR(64),
applied_at TIMESTAMP WITH TIME ZONE
);
CREATE INDEX IF NOT EXISTS idx_scm_adjustment_note_invoice_id ON trans.scm_invoice_adjustment_note(invoice_id);
CREATE INDEX IF NOT EXISTS idx_scm_adjustment_note_supplier_id ON trans.scm_invoice_adjustment_note(supplier_id);
CREATE INDEX IF NOT EXISTS idx_scm_adjustment_note_buyer_id ON trans.scm_invoice_adjustment_note(buyer_id);
CREATE TABLE IF NOT EXISTS trans.scm_invoice_adjustment_status_log (
log_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
note_id UUID NOT NULL REFERENCES trans.scm_invoice_adjustment_note(note_id) ON DELETE CASCADE,
action VARCHAR(20),
from_status VARCHAR(20),
to_status VARCHAR(20),
remarks TEXT,
performed_by VARCHAR(64),
performed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================================
-- Spa Partner Orders
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.spa_partner_orders (
order_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
order_number VARCHAR(50) UNIQUE NOT NULL,
partner_id VARCHAR(50) NOT NULL,
merchant_id VARCHAR(50) NOT NULL,
order_status VARCHAR(30) NOT NULL,
total_amount NUMERIC(12, 2) NOT NULL,
tax_amount NUMERIC(12, 2),
discount_amount NUMERIC(12, 2),
net_amount NUMERIC(12, 2),
payment_status VARCHAR(30),
payment_mode VARCHAR(30),
delivery_address TEXT,
city VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS trans.spa_partner_order_items (
id SERIAL PRIMARY KEY,
order_id UUID NOT NULL REFERENCES trans.spa_partner_orders(order_id),
product_id VARCHAR(50) NOT NULL,
product_name VARCHAR(200),
quantity INTEGER NOT NULL,
unit_price NUMERIC(10, 2) NOT NULL,
tax_percent NUMERIC(5, 2),
total_price NUMERIC(12, 2)
);
-- ============================================================================
-- Trade Returns
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.scm_return (
return_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
return_no VARCHAR(50) UNIQUE NOT NULL,
return_type VARCHAR(20) NOT NULL CHECK (return_type IN ('PURCHASE', 'SALES')),
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT' CHECK (status IN ('DRAFT', 'SUBMITTED', 'APPROVED', 'COMPLETED', 'REJECTED')),
invoice_id UUID NOT NULL,
invoice_no VARCHAR(50) NOT NULL,
buyer_id VARCHAR(64) NOT NULL,
buyer_name VARCHAR(200) NOT NULL,
supplier_id VARCHAR(64) NOT NULL,
supplier_name VARCHAR(200) NOT NULL,
reason_code VARCHAR(50) NOT NULL CHECK (reason_code IN ('DAMAGED_GOODS', 'EXPIRED_STOCK', 'QUALITY_ISSUE', 'WRONG_ITEM', 'EXCESS_STOCK', 'DEFECTIVE', 'RECALL', 'OTHER')),
remarks TEXT,
dispatch_date TIMESTAMP WITH TIME ZONE,
dispatch_reference VARCHAR(100),
received_date TIMESTAMP WITH TIME ZONE,
received_by VARCHAR(100),
qc_completed_date TIMESTAMP WITH TIME ZONE,
qc_performed_by VARCHAR(100),
created_by VARCHAR(64) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_by VARCHAR(64),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_scm_return_invoice_id ON trans.scm_return(invoice_id);
CREATE INDEX IF NOT EXISTS idx_scm_return_buyer_id ON trans.scm_return(buyer_id);
CREATE INDEX IF NOT EXISTS idx_scm_return_supplier_id ON trans.scm_return(supplier_id);
CREATE INDEX IF NOT EXISTS idx_scm_return_status ON trans.scm_return(status);
CREATE TABLE IF NOT EXISTS trans.scm_return_item (
return_item_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
return_id UUID NOT NULL REFERENCES trans.scm_return(return_id) ON DELETE CASCADE,
invoice_item_id UUID NOT NULL,
catalogue_id UUID NOT NULL,
sku VARCHAR(64) NOT NULL,
description VARCHAR(500) NOT NULL,
batch_no VARCHAR(50) NOT NULL,
expiry_date TIMESTAMP WITH TIME ZONE,
return_qty NUMERIC(12, 3) NOT NULL,
qc_status VARCHAR(20) NOT NULL DEFAULT 'PENDING' CHECK (qc_status IN ('PENDING', 'ACCEPTED', 'REJECTED')),
qc_qty NUMERIC(12, 3),
qc_rejected_qty NUMERIC(12, 3),
qc_remarks TEXT,
qc_performed_by VARCHAR(100),
qc_performed_at TIMESTAMP WITH TIME ZONE,
unit_price NUMERIC(10, 2),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_scm_return_item_return_id ON trans.scm_return_item(return_id);
CREATE INDEX IF NOT EXISTS idx_scm_return_item_invoice_item_id ON trans.scm_return_item(invoice_item_id);
CREATE INDEX IF NOT EXISTS idx_scm_return_item_sku ON trans.scm_return_item(sku);
CREATE TABLE IF NOT EXISTS trans.scm_return_status_log (
log_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
return_id UUID NOT NULL REFERENCES trans.scm_return(return_id) ON DELETE CASCADE,
action VARCHAR(20) NOT NULL,
from_status VARCHAR(20),
to_status VARCHAR(20) NOT NULL,
performed_by VARCHAR(64) NOT NULL,
performed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
remarks TEXT,
reference_no VARCHAR(100)
);
CREATE INDEX IF NOT EXISTS idx_scm_return_status_log_return_id ON trans.scm_return_status_log(return_id);
-- ============================================================================
-- Legacy Sales Orders (B2C)
-- ============================================================================
CREATE TABLE IF NOT EXISTS trans.branches (
branch_id VARCHAR(26) PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS trans.merchants (
merchant_id VARCHAR(26) PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS trans.customers (
customer_id VARCHAR(26) PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS trans.users (
user_id VARCHAR(26) PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS trans.catalogues (
catalogue_id VARCHAR(26) PRIMARY KEY
);
CREATE TABLE IF NOT EXISTS trans.sales_orders (
sales_order_id VARCHAR(26) PRIMARY KEY,
order_number VARCHAR(50) UNIQUE NOT NULL,
branch_id VARCHAR(26) NOT NULL,
merchant_id VARCHAR(26) NOT NULL,
order_date TIMESTAMP WITH TIME ZONE NOT NULL,
status VARCHAR(20) NOT NULL CHECK (status IN ('draft', 'confirmed', 'processing', 'fulfilled', 'partially_fulfilled', 'cancelled', 'on_hold')),
customer_id VARCHAR(26) NOT NULL,
customer_name VARCHAR(255) NOT NULL,
customer_type VARCHAR(10) NOT NULL CHECK (customer_type IN ('b2b', 'b2c')),
customer_phone VARCHAR(20),
customer_email VARCHAR(255),
customer_gstin VARCHAR(15),
subtotal DECIMAL(12,2) NOT NULL DEFAULT 0,
total_discount DECIMAL(12,2) NOT NULL DEFAULT 0,
total_tax DECIMAL(12,2) NOT NULL DEFAULT 0,
shipping_charges DECIMAL(12,2) NOT NULL DEFAULT 0,
grand_total DECIMAL(12,2) NOT NULL DEFAULT 0,
cgst DECIMAL(12,2) DEFAULT 0,
sgst DECIMAL(12,2) DEFAULT 0,
igst DECIMAL(12,2) DEFAULT 0,
payment_type VARCHAR(20) NOT NULL CHECK (payment_type IN ('prepaid', 'cod', 'credit', 'partial')),
payment_status VARCHAR(20) NOT NULL CHECK (payment_status IN ('unpaid', 'partial', 'paid', 'refunded', 'overdue')),
payment_method VARCHAR(50),
payment_date TIMESTAMP WITH TIME ZONE,
payment_reference VARCHAR(100),
amount_paid DECIMAL(12,2) NOT NULL DEFAULT 0,
amount_due DECIMAL(12,2) NOT NULL DEFAULT 0,
credit_terms VARCHAR(50),
credit_limit DECIMAL(12,2),
fulfillment_status VARCHAR(20) NOT NULL CHECK (fulfillment_status IN ('pending', 'allocated', 'picked', 'packed', 'shipped', 'delivered')),
expected_delivery_date DATE,
actual_delivery_date DATE,
invoice_id VARCHAR(26),
invoice_number VARCHAR(50),
invoice_date TIMESTAMP WITH TIME ZONE,
invoice_pdf_url TEXT,
notes TEXT,
internal_notes TEXT,
created_by VARCHAR(26) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
approved_by VARCHAR(26),
approved_at TIMESTAMP WITH TIME ZONE,
source VARCHAR(20) DEFAULT 'web',
channel VARCHAR(50),
tags TEXT[],
version INTEGER NOT NULL DEFAULT 1,
CONSTRAINT fk_sales_order_branch FOREIGN KEY (branch_id) REFERENCES trans.branches(branch_id),
CONSTRAINT fk_sales_order_merchant FOREIGN KEY (merchant_id) REFERENCES trans.merchants(merchant_id),
CONSTRAINT fk_sales_order_customer FOREIGN KEY (customer_id) REFERENCES trans.customers(customer_id),
CONSTRAINT fk_sales_order_created_by FOREIGN KEY (created_by) REFERENCES trans.users(user_id)
);
CREATE TABLE IF NOT EXISTS trans.sales_order_items (
id VARCHAR(26) PRIMARY KEY,
sales_order_id VARCHAR(26) NOT NULL,
sku VARCHAR(50) NOT NULL,
product_id VARCHAR(26) NOT NULL,
product_name VARCHAR(255) NOT NULL,
item_type VARCHAR(20) NOT NULL CHECK (item_type IN ('product', 'service')),
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price DECIMAL(10,2) NOT NULL,
tax_percent DECIMAL(5,2) NOT NULL DEFAULT 0,
discount_percent DECIMAL(5,2) NOT NULL DEFAULT 0,
line_total DECIMAL(12,2) NOT NULL,
hsn_code VARCHAR(10),
uom VARCHAR(20) NOT NULL,
batch_no VARCHAR(50),
serials TEXT[],
staff_id VARCHAR(26),
staff_name VARCHAR(255),
remarks TEXT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_sales_order_item_order FOREIGN KEY (sales_order_id) REFERENCES trans.sales_orders(sales_order_id) ON DELETE CASCADE,
CONSTRAINT fk_sales_order_item_product FOREIGN KEY (product_id) REFERENCES trans.catalogues(catalogue_id)
);
CREATE TABLE IF NOT EXISTS trans.sales_order_addresses (
id VARCHAR(26) PRIMARY KEY,
sales_order_id VARCHAR(26) NOT NULL,
address_type VARCHAR(20) NOT NULL CHECK (address_type IN ('billing', 'shipping')),
line1 VARCHAR(255) NOT NULL,
line2 VARCHAR(255),
city VARCHAR(100) NOT NULL,
state VARCHAR(100) NOT NULL,
postal_code VARCHAR(20) NOT NULL,
country VARCHAR(100) NOT NULL DEFAULT 'India',
landmark VARCHAR(255),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_sales_order_address FOREIGN KEY (sales_order_id) REFERENCES trans.sales_orders(sales_order_id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS trans.sales_order_shipments (
shipment_id VARCHAR(26) PRIMARY KEY,
sales_order_id VARCHAR(26) NOT NULL,
carrier VARCHAR(100),
tracking_number VARCHAR(100),
awb_number VARCHAR(100),
shipping_method VARCHAR(50),
dispatch_date TIMESTAMP WITH TIME ZONE,
expected_delivery_date DATE,
actual_delivery_date DATE,
status VARCHAR(20) CHECK (status IN ('pending', 'picked', 'in_transit', 'out_for_delivery', 'delivered', 'failed')),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_sales_order_shipment FOREIGN KEY (sales_order_id) REFERENCES trans.sales_orders(sales_order_id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS trans.sales_order_documents (
id VARCHAR(26) PRIMARY KEY,
sales_order_id VARCHAR(26) NOT NULL,
filename VARCHAR(255) NOT NULL,
file_url TEXT NOT NULL,
document_type VARCHAR(50) NOT NULL,
file_size INTEGER,
mime_type VARCHAR(100),
uploaded_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
uploaded_by VARCHAR(26),
CONSTRAINT fk_sales_order_document FOREIGN KEY (sales_order_id) REFERENCES trans.sales_orders(sales_order_id) ON DELETE CASCADE
);
-- ============================================================================
-- Additional Indexes for Performance Optimization
-- ============================================================================
-- Invoice Adjustment Note Indexes
CREATE INDEX IF NOT EXISTS idx_scm_adjustment_note_status ON trans.scm_invoice_adjustment_note(status);
CREATE INDEX IF NOT EXISTS idx_scm_adjustment_note_type ON trans.scm_invoice_adjustment_note(note_type);
CREATE INDEX IF NOT EXISTS idx_scm_adjustment_note_category ON trans.scm_invoice_adjustment_note(category_code);
CREATE INDEX IF NOT EXISTS idx_scm_adjustment_note_date ON trans.scm_invoice_adjustment_note(note_date);
-- Trade Return Composite Indexes
CREATE INDEX IF NOT EXISTS idx_returns_type_status ON trans.scm_return (return_type, status);
CREATE INDEX IF NOT EXISTS idx_returns_buyer_status ON trans.scm_return (buyer_id, status);
CREATE INDEX IF NOT EXISTS idx_returns_supplier_status ON trans.scm_return (supplier_id, status);
CREATE INDEX IF NOT EXISTS idx_returns_invoice_type ON trans.scm_return (invoice_id, return_type);
CREATE INDEX IF NOT EXISTS idx_returns_created_status ON trans.scm_return (created_at, status);
-- Trade Return Item Indexes
CREATE INDEX IF NOT EXISTS idx_return_items_sku_batch ON trans.scm_return_item (sku, batch_no);
CREATE INDEX IF NOT EXISTS idx_return_items_qc_status ON trans.scm_return_item (qc_status);
CREATE INDEX IF NOT EXISTS idx_return_items_catalogue_batch ON trans.scm_return_item (catalogue_id, batch_no);
-- Trade Return Log Indexes
CREATE INDEX IF NOT EXISTS idx_return_logs_action_date ON trans.scm_return_status_log (action, performed_at);
CREATE INDEX IF NOT EXISTS idx_return_logs_status_date ON trans.scm_return_status_log (to_status, performed_at);
|