////////////////////////////////////////////////////////////
// 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)
  }
}