docs: remove stale root NewERD.txt (superseded by docs/NewERD.txt v2.6)
This commit is contained in:
-787
@@ -1,787 +0,0 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// PROCUREMENT + INVENTORY SYSTEM
|
||||
// FINAL INTEGRATED ER (FOR DBDATALYZER / DBDATADIAGRAM.IO)
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ENUMS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
enum quote_status {
|
||||
offered
|
||||
accepted
|
||||
arrived
|
||||
rejected
|
||||
expired
|
||||
}
|
||||
|
||||
enum termsheet_status {
|
||||
offered
|
||||
accepted
|
||||
rejected
|
||||
}
|
||||
|
||||
enum material_status {
|
||||
active
|
||||
discontinued
|
||||
draft
|
||||
}
|
||||
|
||||
enum attribute_data_type {
|
||||
number
|
||||
integer
|
||||
string
|
||||
enum
|
||||
boolean
|
||||
date
|
||||
}
|
||||
|
||||
enum discount_type {
|
||||
none
|
||||
percent
|
||||
fixed
|
||||
}
|
||||
|
||||
enum item_decision_status {
|
||||
pending
|
||||
chosen
|
||||
rejected
|
||||
}
|
||||
|
||||
enum quote_event_type {
|
||||
offered
|
||||
accepted
|
||||
rejected
|
||||
arrived
|
||||
note
|
||||
edited
|
||||
expired
|
||||
}
|
||||
|
||||
enum inventory_transaction_reason {
|
||||
PURCHASE
|
||||
WITHDRAWAL
|
||||
RETURN
|
||||
TRANSFER_IN
|
||||
TRANSFER_OUT
|
||||
DAMAGE
|
||||
WASTE
|
||||
LOSS
|
||||
FOUND
|
||||
STOCK_COUNT
|
||||
OTHER
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// USERS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table users {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
first_name text [not null]
|
||||
last_name text [not null]
|
||||
phone text
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// CATALOG
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table units {
|
||||
id integer [pk]
|
||||
|
||||
code varchar [not null, unique]
|
||||
name_fa varchar
|
||||
|
||||
dimension varchar
|
||||
si_factor decimal [not null, default: 1.0]
|
||||
is_base boolean [default: false]
|
||||
}
|
||||
|
||||
|
||||
Table brands {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
name text [not null]
|
||||
country text
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
indexes {
|
||||
(name, country) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Table material_categories {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
slug text [not null, unique]
|
||||
name text [not null]
|
||||
description text
|
||||
|
||||
is_active boolean [
|
||||
not null,
|
||||
default: true
|
||||
]
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
updated_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Table attribute_definitions {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
attribute_key text [not null, unique]
|
||||
label text [not null]
|
||||
|
||||
data_type attribute_data_type [not null]
|
||||
|
||||
unit_id integer [
|
||||
ref: > units.id
|
||||
]
|
||||
|
||||
enum_values jsonb
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Table category_attributes {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
category_id uuid [
|
||||
not null,
|
||||
ref: > material_categories.id
|
||||
]
|
||||
|
||||
attribute_definition_id uuid [
|
||||
not null,
|
||||
ref: > attribute_definitions.id
|
||||
]
|
||||
|
||||
is_required boolean [
|
||||
not null,
|
||||
default: false
|
||||
]
|
||||
|
||||
is_filterable boolean [
|
||||
not null,
|
||||
default: false
|
||||
]
|
||||
|
||||
conditional_rules jsonb
|
||||
|
||||
sort_order smallint [
|
||||
not null,
|
||||
default: 0
|
||||
]
|
||||
|
||||
indexes {
|
||||
(category_id, attribute_definition_id) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Table materials {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
category_id uuid [
|
||||
not null,
|
||||
ref: > material_categories.id
|
||||
]
|
||||
|
||||
name text [not null]
|
||||
|
||||
// Main unit of the material.
|
||||
// All inventory quantities are stored in this unit.
|
||||
canonical_unit_id integer [
|
||||
not null,
|
||||
ref: > units.id
|
||||
]
|
||||
|
||||
status material_status [
|
||||
not null,
|
||||
default: 'active'
|
||||
]
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
updated_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
indexes {
|
||||
(category_id, name) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Table brand_materials {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
brand_id uuid [
|
||||
not null,
|
||||
ref: > brands.id
|
||||
]
|
||||
|
||||
material_id uuid [
|
||||
not null,
|
||||
ref: > materials.id
|
||||
]
|
||||
|
||||
catalog_code text
|
||||
|
||||
is_active boolean [
|
||||
not null,
|
||||
default: true
|
||||
]
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
indexes {
|
||||
(brand_id, material_id) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Table material_units {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
material_id uuid [
|
||||
not null,
|
||||
ref: > materials.id
|
||||
]
|
||||
|
||||
// NULL = generic unit
|
||||
// Non-NULL = brand-specific unit
|
||||
brand_material_id uuid [
|
||||
ref: > brand_materials.id
|
||||
]
|
||||
|
||||
unit_id integer [
|
||||
not null,
|
||||
ref: > units.id
|
||||
]
|
||||
|
||||
// Converts this unit to materials.canonical_unit_id
|
||||
conversion_factor decimal(18,6) [
|
||||
not null
|
||||
]
|
||||
|
||||
is_default boolean [
|
||||
not null,
|
||||
default: false
|
||||
]
|
||||
|
||||
indexes {
|
||||
(material_id, brand_material_id, unit_id) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Table material_attribute_values {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
material_id uuid [
|
||||
not null,
|
||||
ref: > materials.id
|
||||
]
|
||||
|
||||
attribute_definition_id uuid [
|
||||
not null,
|
||||
ref: > attribute_definitions.id
|
||||
]
|
||||
|
||||
value_number decimal(18,6)
|
||||
value_string text
|
||||
value_boolean boolean
|
||||
value_date date
|
||||
|
||||
indexes {
|
||||
(material_id, attribute_definition_id) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// SUPPLIERS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table suppliers {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
name text [not null]
|
||||
location text
|
||||
phone text
|
||||
contact_person text
|
||||
tax_id text
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// PROJECTS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table projects {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
name text [not null]
|
||||
description text
|
||||
start_date date
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// QUOTATIONS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table quotes {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
supplier_id uuid [
|
||||
not null,
|
||||
ref: > suppliers.id
|
||||
]
|
||||
|
||||
project_id uuid [
|
||||
ref: > projects.id
|
||||
]
|
||||
|
||||
quote_date timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
expiry_date date
|
||||
|
||||
accepted_date timestamptz
|
||||
arrived_date timestamptz
|
||||
|
||||
status quote_status [
|
||||
not null,
|
||||
default: 'offered'
|
||||
]
|
||||
|
||||
is_official boolean [
|
||||
not null,
|
||||
default: true
|
||||
]
|
||||
|
||||
notes text
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
updated_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Table quote_events {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
quote_id uuid [
|
||||
not null,
|
||||
ref: > quotes.id
|
||||
]
|
||||
|
||||
event_type quote_event_type [
|
||||
not null
|
||||
]
|
||||
|
||||
payload jsonb [
|
||||
not null,
|
||||
default: '{}'
|
||||
]
|
||||
|
||||
occurred_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
actor text
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// QUOTATION ITEMS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table line_items {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
quote_id uuid [
|
||||
not null,
|
||||
ref: > quotes.id
|
||||
]
|
||||
|
||||
material_id uuid [
|
||||
not null,
|
||||
ref: > materials.id
|
||||
]
|
||||
|
||||
brand_material_id uuid [
|
||||
ref: > brand_materials.id
|
||||
]
|
||||
|
||||
unit_id integer [
|
||||
not null,
|
||||
ref: > units.id
|
||||
]
|
||||
|
||||
// Ordered / requested quantity
|
||||
quantity decimal(18,4) [
|
||||
not null
|
||||
]
|
||||
|
||||
notes text
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Table line_item_specs {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
line_item_id uuid [
|
||||
not null,
|
||||
ref: > line_items.id
|
||||
]
|
||||
|
||||
attribute_definition_id uuid [
|
||||
not null,
|
||||
ref: > attribute_definitions.id
|
||||
]
|
||||
|
||||
value_number decimal(18,6)
|
||||
value_string text
|
||||
value_boolean boolean
|
||||
value_date date
|
||||
|
||||
unit_id_at_time integer [
|
||||
ref: > units.id
|
||||
]
|
||||
|
||||
indexes {
|
||||
(line_item_id, attribute_definition_id) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// TERMSHEETS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table termsheets {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
quote_id uuid [
|
||||
not null,
|
||||
ref: > quotes.id
|
||||
]
|
||||
|
||||
label text [not null]
|
||||
|
||||
status termsheet_status [
|
||||
not null,
|
||||
default: 'offered'
|
||||
]
|
||||
|
||||
discount_type discount_type [
|
||||
not null,
|
||||
default: 'none'
|
||||
]
|
||||
|
||||
discount_value decimal(18,4) [
|
||||
not null,
|
||||
default: 0
|
||||
]
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Table termsheet_schedule_steps {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
termsheet_id uuid [
|
||||
not null,
|
||||
ref: > termsheets.id
|
||||
]
|
||||
|
||||
step_no smallint [
|
||||
not null
|
||||
]
|
||||
|
||||
due_date date [
|
||||
not null
|
||||
]
|
||||
|
||||
amount decimal(18,2) [
|
||||
not null
|
||||
]
|
||||
|
||||
note text
|
||||
|
||||
indexes {
|
||||
(termsheet_id, step_no) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ITEM TERMSHEETS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table item_termsheets {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
line_item_id uuid [
|
||||
not null,
|
||||
ref: > line_items.id
|
||||
]
|
||||
|
||||
termsheet_id uuid [
|
||||
not null,
|
||||
ref: > termsheets.id
|
||||
]
|
||||
|
||||
unit_price decimal(18,4) [
|
||||
not null
|
||||
]
|
||||
|
||||
min_order_qty decimal(18,4)
|
||||
|
||||
total_price decimal(18,2)
|
||||
|
||||
indexes {
|
||||
(line_item_id, termsheet_id) [unique]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// ITEM DECISIONS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table item_decisions {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
line_item_id uuid [
|
||||
not null,
|
||||
unique,
|
||||
ref: - line_items.id
|
||||
]
|
||||
|
||||
chosen_item_termsheet_id uuid [
|
||||
ref: > item_termsheets.id
|
||||
]
|
||||
|
||||
status item_decision_status [
|
||||
not null,
|
||||
default: 'pending'
|
||||
]
|
||||
|
||||
adjusted_unit_price decimal(18,4)
|
||||
|
||||
adjusted_notes text
|
||||
|
||||
decided_at timestamptz
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// WAREHOUSES
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table warehouses {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
project_id uuid [
|
||||
not null,
|
||||
ref: > projects.id
|
||||
]
|
||||
|
||||
name text [not null]
|
||||
|
||||
description text
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// WAREHOUSE ACCESS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table warehouse_users {
|
||||
warehouse_id uuid [
|
||||
not null,
|
||||
ref: > warehouses.id
|
||||
]
|
||||
|
||||
user_id uuid [
|
||||
not null,
|
||||
ref: > users.id
|
||||
]
|
||||
|
||||
indexes {
|
||||
(warehouse_id, user_id) [pk]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// CURRENT INVENTORY SNAPSHOT
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table inventory {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
warehouse_id uuid [
|
||||
not null,
|
||||
ref: > warehouses.id
|
||||
]
|
||||
|
||||
material_id uuid [
|
||||
not null,
|
||||
ref: > materials.id
|
||||
]
|
||||
|
||||
brand_id uuid [
|
||||
ref: > brands.id
|
||||
]
|
||||
|
||||
item_title text [not null]
|
||||
|
||||
specs jsonb [default: '{}']
|
||||
|
||||
// SHA256 of sorted canonical specs JSON (or 'default' if empty)
|
||||
specs_hash varchar(64) [
|
||||
not null,
|
||||
default: 'default'
|
||||
]
|
||||
|
||||
quantity decimal(18,6) [
|
||||
not null,
|
||||
default: 0
|
||||
]
|
||||
|
||||
updated_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
indexes {
|
||||
(warehouse_id, material_id, brand_id, specs_hash) [unique]
|
||||
(warehouse_id, item_title)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// INVENTORY TRANSACTIONS
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Table inventory_transactions {
|
||||
id uuid [pk, default: `gen_random_uuid()`]
|
||||
|
||||
inventory_id uuid [
|
||||
not null,
|
||||
ref: > inventory.id
|
||||
]
|
||||
|
||||
warehouse_id uuid [
|
||||
not null,
|
||||
ref: > warehouses.id
|
||||
]
|
||||
|
||||
line_item_id uuid [
|
||||
ref: >? line_items.id
|
||||
]
|
||||
|
||||
quantity decimal(18,6) [
|
||||
not null
|
||||
]
|
||||
|
||||
reason inventory_transaction_reason [
|
||||
not null
|
||||
]
|
||||
|
||||
performed_by uuid [
|
||||
not null,
|
||||
ref: > users.id
|
||||
]
|
||||
|
||||
transaction_date timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
note text
|
||||
|
||||
created_at timestamptz [
|
||||
not null,
|
||||
default: `now()`
|
||||
]
|
||||
|
||||
indexes {
|
||||
(inventory_id, transaction_date)
|
||||
(warehouse_id, transaction_date)
|
||||
(inventory_id, line_item_id)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user