feat: cash advance
This commit is contained in:
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS cash_advances;
|
||||
@@ -0,0 +1,45 @@
|
||||
-- A cash advance is money handed to a team up front so the team can go shopping
|
||||
-- (kasbon in the Indonesian UI). It is deliberately not an expense: while the money
|
||||
-- sits with the team it is still the outlet's, and what was actually spent is read
|
||||
-- from the purchase orders and expenses charged back to the advance. Nothing about
|
||||
-- that spending is copied here.
|
||||
CREATE TABLE cash_advances (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
outlet_id UUID NOT NULL REFERENCES outlets(id) ON DELETE CASCADE,
|
||||
code_number VARCHAR(50) NOT NULL,
|
||||
-- Same team shape as purchase_orders, with one difference: an advance is handed
|
||||
-- to a team, so there is no "no team chosen yet" state and team_scope is NOT NULL.
|
||||
team_scope VARCHAR(20) NOT NULL,
|
||||
team_category_id UUID REFERENCES categories(id) ON DELETE RESTRICT,
|
||||
amount DECIMAL(15,2) NOT NULL DEFAULT 0,
|
||||
-- Cash the team brought back unspent. Spending is not stored: it is summed from
|
||||
-- the purchase orders and expenses that point at this advance.
|
||||
returned_amount DECIMAL(15,2) NOT NULL DEFAULT 0,
|
||||
issued_date DATE NOT NULL,
|
||||
due_date DATE,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'draft',
|
||||
description TEXT,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
|
||||
-- Written as a CASE for the same reason as purchase_orders: an OR chain would
|
||||
-- evaluate to NULL for an unexpected scope and a CHECK only rejects FALSE.
|
||||
CONSTRAINT chk_cash_advances_team CHECK (
|
||||
CASE
|
||||
WHEN team_scope = 'category' THEN team_category_id IS NOT NULL
|
||||
WHEN team_scope = 'central' THEN team_category_id IS NULL
|
||||
ELSE false
|
||||
END
|
||||
),
|
||||
CONSTRAINT chk_cash_advances_amounts CHECK (amount >= 0 AND returned_amount >= 0)
|
||||
);
|
||||
|
||||
-- Leading with organization_id means this also serves the plain per-organization
|
||||
-- lookups, so there is no separate index on that column.
|
||||
CREATE UNIQUE INDEX idx_cash_advances_organization_id_code_number ON cash_advances(organization_id, code_number);
|
||||
CREATE INDEX idx_cash_advances_outlet_id ON cash_advances(outlet_id);
|
||||
CREATE INDEX idx_cash_advances_team_category_id ON cash_advances(team_category_id);
|
||||
CREATE INDEX idx_cash_advances_team_scope ON cash_advances(team_scope);
|
||||
CREATE INDEX idx_cash_advances_issued_date ON cash_advances(issued_date);
|
||||
CREATE INDEX idx_cash_advances_status ON cash_advances(status);
|
||||
@@ -0,0 +1,15 @@
|
||||
DROP INDEX IF EXISTS idx_expenses_cash_advance_id;
|
||||
|
||||
ALTER TABLE expenses
|
||||
DROP CONSTRAINT IF EXISTS fk_expenses_cash_advance;
|
||||
|
||||
ALTER TABLE expenses
|
||||
DROP COLUMN IF EXISTS cash_advance_id;
|
||||
|
||||
DROP INDEX IF EXISTS idx_purchase_orders_cash_advance_id;
|
||||
|
||||
ALTER TABLE purchase_orders
|
||||
DROP CONSTRAINT IF EXISTS fk_purchase_orders_cash_advance;
|
||||
|
||||
ALTER TABLE purchase_orders
|
||||
DROP COLUMN IF EXISTS cash_advance_id;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- Spending paid out of a cash advance points back at it. This is how an advance is
|
||||
-- accounted for: the team's purchases and expenses are the settlement, so the advance
|
||||
-- itself never carries a copy of what was bought.
|
||||
-- RESTRICT rather than SET NULL: dropping an advance that still has spending on it
|
||||
-- would leave that spending looking like it came straight out of the drawer.
|
||||
ALTER TABLE purchase_orders
|
||||
ADD COLUMN IF NOT EXISTS cash_advance_id UUID;
|
||||
|
||||
ALTER TABLE purchase_orders
|
||||
ADD CONSTRAINT fk_purchase_orders_cash_advance
|
||||
FOREIGN KEY (cash_advance_id) REFERENCES cash_advances(id) ON DELETE RESTRICT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_purchase_orders_cash_advance_id
|
||||
ON purchase_orders(cash_advance_id);
|
||||
|
||||
ALTER TABLE expenses
|
||||
ADD COLUMN IF NOT EXISTS cash_advance_id UUID;
|
||||
|
||||
ALTER TABLE expenses
|
||||
ADD CONSTRAINT fk_expenses_cash_advance
|
||||
FOREIGN KEY (cash_advance_id) REFERENCES cash_advances(id) ON DELETE RESTRICT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_expenses_cash_advance_id
|
||||
ON expenses(cash_advance_id);
|
||||
Reference in New Issue
Block a user