Procurement Models ================== Material -------- Catalog of materials used in EV charger installations. .. list-table:: :header-rows: 1 :widths: 20 20 20 40 * - Field - Type - Constraints - Description * - id - UUIDField - PK, default=uuid4 - Primary key * - name - CharField(200) - not null - Material name * - sku - CharField(50) - unique - Stock keeping unit code * - category - CharField(50) - choices: ``charger``, ``cable``, ``mounting``, ``electrical``, ``misc`` - Material category * - unit - CharField(20) - choices: ``piece``, ``meter``, ``kg``, ``set`` - Unit of measurement * - description - TextField - blank - Detailed description MaterialStock ------------- Inventory levels per material per zone. .. list-table:: :header-rows: 1 :widths: 20 20 20 40 * - Field - Type - Constraints - Description * - id - UUIDField - PK, default=uuid4 - Primary key * - material - ForeignKey(Material) - not null, on_delete=CASCADE - Material reference * - zone - ForeignKey(Zone) - not null, on_delete=PROTECT - Stock location zone * - quantity_available - IntegerField - not null, >=0 - Current available stock * - reorder_level - IntegerField - default=5 - Threshold for reorder alerts * - updated_at - DateTimeField - auto_now - Last stock update **Unique constraint**: ``(material, zone)`` MaterialAllocation ------------------ Records material reserved or dispatched for a specific installation. .. list-table:: :header-rows: 1 :widths: 20 20 20 40 * - Field - Type - Constraints - Description * - id - UUIDField - PK, default=uuid4 - Primary key * - installation - ForeignKey(Installation) - not null, on_delete=CASCADE - Target installation * - material - ForeignKey(Material) - not null, on_delete=PROTECT - Allocated material * - quantity - IntegerField - not null, >0 - Quantity allocated * - allocated_by - ForeignKey(User) - not null, on_delete=PROTECT - Procurement staff who allocated * - status - CharField(20) - choices: ``allocated``, ``dispatched``, ``delivered``, ``returned`` - Allocation lifecycle state * - allocated_at - DateTimeField - auto_now_add - Allocation timestamp ProcurementRequest ------------------ Request to procure materials locally when zone stock is insufficient. .. list-table:: :header-rows: 1 :widths: 20 20 20 40 * - Field - Type - Constraints - Description * - id - UUIDField - PK, default=uuid4 - Primary key * - installation - ForeignKey(Installation) - not null, on_delete=CASCADE - For which installation * - material - ForeignKey(Material) - not null, on_delete=PROTECT - What material is needed * - quantity - IntegerField - not null, >0 - Quantity needed * - vendor - ForeignKey(Vendor) - nullable, on_delete=SET_NULL - Local vendor if identified * - status - CharField(20) - choices: ``requested``, ``approved``, ``ordered``, ``received``, ``cancelled`` - Request lifecycle state * - estimated_cost - DecimalField(10,2) - nullable - Expected cost before ordering * - actual_cost - DecimalField(10,2) - nullable - Final cost after receiving * - requested_by - ForeignKey(User) - not null, on_delete=PROTECT - Who created the request * - created_at - DateTimeField - auto_now_add - Request creation timestamp Vendor ------ Local suppliers for material procurement. .. list-table:: :header-rows: 1 :widths: 20 20 20 40 * - Field - Type - Constraints - Description * - id - UUIDField - PK, default=uuid4 - Primary key * - name - CharField(200) - not null - Vendor business name * - phone - CharField(15) - not null - Contact number * - zone - ForeignKey(Zone) - not null, on_delete=PROTECT - Vendor's operating zone * - upi_id - CharField(100) - nullable - UPI/QR payment identifier * - bank_account - CharField(20) - nullable - Bank account number * - bank_ifsc - CharField(15) - nullable - Bank IFSC code * - is_active - BooleanField - default=True - Whether vendor is active **Note**: At least one payment method (``upi_id`` or ``bank_account`` + ``bank_ifsc``) should be provided, enforced at the application level.