Add coa purchase and vendors

This commit is contained in:
Aditya Siregar
2025-09-12 01:12:11 +07:00
parent c107733add
commit efe09c21e4
86 changed files with 8517 additions and 212 deletions
@@ -0,0 +1,2 @@
-- Drop vendors table
DROP TABLE IF EXISTS vendors;
@@ -0,0 +1,22 @@
-- Vendors table
CREATE TABLE vendors (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
email VARCHAR(255),
phone_number VARCHAR(20),
address TEXT,
contact_person VARCHAR(255),
tax_number VARCHAR(50),
payment_terms VARCHAR(100),
notes TEXT,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_vendors_organization_id ON vendors(organization_id);
CREATE INDEX idx_vendors_name ON vendors(name);
CREATE INDEX idx_vendors_email ON vendors(email);
CREATE INDEX idx_vendors_is_active ON vendors(is_active);
CREATE INDEX idx_vendors_created_at ON vendors(created_at);
@@ -0,0 +1,4 @@
-- Drop purchase order tables
DROP TABLE IF EXISTS purchase_order_attachments;
DROP TABLE IF EXISTS purchase_order_items;
DROP TABLE IF EXISTS purchase_orders;
@@ -0,0 +1,54 @@
-- Purchase Orders table
CREATE TABLE purchase_orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
vendor_id UUID NOT NULL REFERENCES vendors(id) ON DELETE CASCADE,
po_number VARCHAR(50) NOT NULL,
transaction_date DATE NOT NULL,
due_date DATE NOT NULL,
reference VARCHAR(100),
status VARCHAR(20) NOT NULL DEFAULT 'draft' CHECK (status IN ('draft', 'sent', 'approved', 'received', 'cancelled')),
message TEXT,
total_amount DECIMAL(15,2) NOT NULL DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Purchase Order Items table
CREATE TABLE purchase_order_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
purchase_order_id UUID NOT NULL REFERENCES purchase_orders(id) ON DELETE CASCADE,
ingredient_id UUID NOT NULL REFERENCES ingredients(id) ON DELETE CASCADE,
description TEXT,
quantity DECIMAL(10,3) NOT NULL,
unit_id UUID NOT NULL REFERENCES units(id) ON DELETE CASCADE,
amount DECIMAL(15,2) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Purchase Order Attachments table
CREATE TABLE purchase_order_attachments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
purchase_order_id UUID NOT NULL REFERENCES purchase_orders(id) ON DELETE CASCADE,
file_id UUID NOT NULL REFERENCES files(id) ON DELETE CASCADE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_purchase_orders_organization_id ON purchase_orders(organization_id);
CREATE INDEX idx_purchase_orders_vendor_id ON purchase_orders(vendor_id);
CREATE INDEX idx_purchase_orders_po_number ON purchase_orders(po_number);
CREATE INDEX idx_purchase_orders_status ON purchase_orders(status);
CREATE INDEX idx_purchase_orders_transaction_date ON purchase_orders(transaction_date);
CREATE INDEX idx_purchase_orders_created_at ON purchase_orders(created_at);
CREATE INDEX idx_purchase_order_items_purchase_order_id ON purchase_order_items(purchase_order_id);
CREATE INDEX idx_purchase_order_items_ingredient_id ON purchase_order_items(ingredient_id);
CREATE INDEX idx_purchase_order_items_unit_id ON purchase_order_items(unit_id);
CREATE INDEX idx_purchase_order_attachments_purchase_order_id ON purchase_order_attachments(purchase_order_id);
CREATE INDEX idx_purchase_order_attachments_file_id ON purchase_order_attachments(file_id);
-- Unique constraint for PO number per organization
CREATE UNIQUE INDEX idx_purchase_orders_po_number_org ON purchase_orders(organization_id, po_number);
@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS ingredient_unit_converters;
@@ -0,0 +1,33 @@
CREATE TABLE ingredient_unit_converters (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
ingredient_id UUID NOT NULL REFERENCES ingredients(id) ON DELETE CASCADE,
from_unit_id UUID NOT NULL REFERENCES units(id) ON DELETE CASCADE,
to_unit_id UUID NOT NULL REFERENCES units(id) ON DELETE CASCADE,
conversion_factor DECIMAL(15,6) NOT NULL CHECK (conversion_factor > 0),
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
updated_by UUID NOT NULL REFERENCES users(id) ON DELETE RESTRICT
);
-- Create indexes for better performance
CREATE INDEX idx_ingredient_unit_converters_organization_id ON ingredient_unit_converters(organization_id);
CREATE INDEX idx_ingredient_unit_converters_ingredient_id ON ingredient_unit_converters(ingredient_id);
CREATE INDEX idx_ingredient_unit_converters_from_unit_id ON ingredient_unit_converters(from_unit_id);
CREATE INDEX idx_ingredient_unit_converters_to_unit_id ON ingredient_unit_converters(to_unit_id);
CREATE INDEX idx_ingredient_unit_converters_active ON ingredient_unit_converters(is_active);
-- Create unique constraint to prevent duplicate converters for the same ingredient and unit pair
CREATE UNIQUE INDEX idx_ingredient_unit_converters_unique
ON ingredient_unit_converters(organization_id, ingredient_id, from_unit_id, to_unit_id)
WHERE is_active = true;
-- Add comments for documentation
COMMENT ON TABLE ingredient_unit_converters IS 'Stores unit conversion factors for ingredients within an organization';
COMMENT ON COLUMN ingredient_unit_converters.conversion_factor IS 'How many from_unit_id units equal one to_unit_id unit (e.g., 1000 for grams to kilograms)';
COMMENT ON COLUMN ingredient_unit_converters.is_active IS 'Whether this conversion is currently active and can be used';
COMMENT ON COLUMN ingredient_unit_converters.created_by IS 'User who created this conversion rule';
COMMENT ON COLUMN ingredient_unit_converters.updated_by IS 'User who last updated this conversion rule';
@@ -0,0 +1 @@
DROP TABLE IF EXISTS chart_of_account_types;
@@ -0,0 +1,20 @@
CREATE TABLE chart_of_account_types (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL,
code VARCHAR(10) NOT NULL UNIQUE,
description TEXT,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Insert default chart of account types
INSERT INTO chart_of_account_types (name, code, description) VALUES
('Assets', 'ASSET', 'Resources owned by the organization'),
('Liabilities', 'LIABILITY', 'Debts and obligations'),
('Equity', 'EQUITY', 'Owner''s interest in the organization'),
('Revenue', 'REVENUE', 'Income from business operations'),
('Expenses', 'EXPENSE', 'Costs incurred in business operations');
CREATE INDEX idx_chart_of_account_types_code ON chart_of_account_types(code);
CREATE INDEX idx_chart_of_account_types_is_active ON chart_of_account_types(is_active);
@@ -0,0 +1 @@
DROP TABLE IF EXISTS chart_of_accounts;
@@ -0,0 +1,24 @@
CREATE TABLE chart_of_accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
outlet_id UUID REFERENCES outlets(id) ON DELETE CASCADE,
chart_of_account_type_id UUID NOT NULL REFERENCES chart_of_account_types(id) ON DELETE RESTRICT,
parent_id UUID REFERENCES chart_of_accounts(id) ON DELETE SET NULL,
name VARCHAR(255) NOT NULL,
code VARCHAR(20) NOT NULL,
description TEXT,
is_active BOOLEAN DEFAULT true,
is_system BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(organization_id, outlet_id, code),
UNIQUE(organization_id, code) -- For organization-level accounts
);
CREATE INDEX idx_chart_of_accounts_organization_id ON chart_of_accounts(organization_id);
CREATE INDEX idx_chart_of_accounts_outlet_id ON chart_of_accounts(outlet_id);
CREATE INDEX idx_chart_of_accounts_type_id ON chart_of_accounts(chart_of_account_type_id);
CREATE INDEX idx_chart_of_accounts_parent_id ON chart_of_accounts(parent_id);
CREATE INDEX idx_chart_of_accounts_code ON chart_of_accounts(code);
CREATE INDEX idx_chart_of_accounts_is_active ON chart_of_accounts(is_active);
CREATE INDEX idx_chart_of_accounts_is_system ON chart_of_accounts(is_system);
@@ -0,0 +1 @@
DROP TABLE IF EXISTS accounts;
@@ -0,0 +1,26 @@
CREATE TABLE accounts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
outlet_id UUID REFERENCES outlets(id) ON DELETE CASCADE,
chart_of_account_id UUID NOT NULL REFERENCES chart_of_accounts(id) ON DELETE RESTRICT,
name VARCHAR(255) NOT NULL,
number VARCHAR(50) NOT NULL,
account_type VARCHAR(20) NOT NULL CHECK (account_type IN ('cash', 'wallet', 'bank', 'credit', 'debit', 'asset', 'liability', 'equity', 'revenue', 'expense')),
opening_balance DECIMAL(15,2) DEFAULT 0.00,
current_balance DECIMAL(15,2) DEFAULT 0.00,
description TEXT,
is_active BOOLEAN DEFAULT true,
is_system BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(organization_id, outlet_id, number),
UNIQUE(organization_id, number) -- For organization-level accounts
);
CREATE INDEX idx_accounts_organization_id ON accounts(organization_id);
CREATE INDEX idx_accounts_outlet_id ON accounts(outlet_id);
CREATE INDEX idx_accounts_chart_of_account_id ON accounts(chart_of_account_id);
CREATE INDEX idx_accounts_number ON accounts(number);
CREATE INDEX idx_accounts_account_type ON accounts(account_type);
CREATE INDEX idx_accounts_is_active ON accounts(is_active);
CREATE INDEX idx_accounts_is_system ON accounts(is_system);