G Gaia

Switch factory

CYTO-11 — Balakong Jaya CTSB CYTO-29 CTSB CYTOWELL-54 — Taming Jaya PIC/S CTWSB CYTOCNGZ-602 — Guangzhou CTCNGZ

Only factories you are granted appear here (Filament tenant menu).

Leo Lim

leo@navi.my · Owner / Admin

Profile settings Change password

Theme

Sign out
RetailSellR&DMakeBuyStockPlanItemsGMPOpsAdminInsights

Materials

+ New material
Name Variant code / SKU Type Category Origin Default supplier Default purchase price Default sales price
Showing 1–18 of 431 (sample rows from Katana snapshot)

Project Gaia — static mockup in Filament v3 table idiom. No backend. Sample data: Katana tenant snapshot 2026-04-12.

Materials — field manifest

FieldFilament componentTypeSourceFK target
NameTextColumn::searchable(isIndividual)->url()->sortable()string (material / variant)derived display: '{name} / {variant code | supplier tag}' — keep name and variant code as distinct stored fieldsvariants.id
Variant code / SKUTextColumn::searchable(isIndividual)string, nullablestored per variant, optional (empty on "BBeast Men's Candy Sachet"); can differ from Name suffix (Belgian Dark Cocoa → CBADCP22PLARO91B)
Item typeTextColumn::badge() + SelectFilterenum, mandatorystored: items.item_type — raw_material | packaging | finished_good | consumable. Master classification axis, independent of category; rendered as the gray Type badge
Category groupTextColumn (parent) + SelectFilterFK, admin-lockedstored: items.category_group_id — 5 admin-locked parents (Actives & Botanicals, Sweeteners, Flavor & Acids, Functional aids, Base powders); shown as the small group label under the category badgecategory_groups.id
CategoryTextColumn::badge() + SelectFilter (grouped by category group)FK, admin-lockedstored: items.category_id — admin-locked child of a category group (~22 clean values). Clean names only: the units-style alias map strips the legacy "(China)" prefix on import ("(China) Actives" → category Actives + origin_country China) and folds the known typos (fruit → Fruit Powder, sweet → Sweetener, "OIl Powder" → Oil Powder)categories.id
Origin countryTextColumn + SelectFilterenum / FK, admin-lockedstored: items.origin_country — authoritative country of origin (NPRA); the value each recipe/BOM Origin column inherits per ingredient. Seeded from the stripped "(China)" prefix, else supplier country (China, Malaysia, Italy, India, Indonesia, Belgium …)countries.id
Customer-suppliedIconColumn / badge + Toggleboolstored: items.customer_supplied — customer-paid packaging (RM0 cost to Cyto); shown only on packaging items as the teal "Customer-supplied" badge
Default supplierTextColumn::placeholder('—')string, nullablestored FK — unpopulated across the snapshot despite supplier names embedded in Name stringssuppliers.id
Default purchase priceTextColumn::money('MYR')money MYRstored default unit cost; defaults to 0 MYR when unset (every visible row 0)
Default sales priceTextColumn::money('MYR')->placeholder('')money MYR, nullablestored, optional — populated only on materials also sold directly (2 of 18 sample rows)
Active / Archive tabsTabs (lifecycle filter); Archive view not capturedbool flagstored: items.archived_at
Bulk actionsBulkAction: Bulk edit / Archive / Delete (+ Print, Export header actions)actionKatana toolbar icon cluster (print, edit, export/archive, trash)

Engine notes

  • Header count "431 items" = total materials in Active state, not just rendered rows.
  • Item classification is now four fields, not one overloaded "category" tag: item_type (enum) · category_group_idcategory_id (admin-locked 5→~22 tree) · customer_supplied (bool) · origin_country. The legacy "(China) Actives / (China) Additives / (China) Flavor / (China) Fruit Powders" values are split on import — clean category into category_id, country into origin_country — via the same alias-map mechanism as the units import (psc→pcs).
  • Name is a computed display string '{name} / {variant code | supplier tag}' while SKU is stored separately — schema keeps them distinct and derives the label.
  • Default purchase price defaults to 0 MYR when unset — money stored as (amount, currency), account base currency MYR.
  • Default sales price is nullable/blank rather than defaulted to 0 — only materials flagged sellable get a value.
  • No stock quantities, committed/available, or cost columns here — inventory figures live in the Stock module; this screen is pure item master data.
  • "Import done." toast in capture — materials support bulk CSV import with completion notification. Imported unit codes pass through the units alias map (psc→pcs, KG→kg, gg→g) — variants.uom_id is FK → the admin-locked units table; staff never type units, conversion factors (kg→mg) are hard-coded.
  • No totals/footer row; list sorted ascending by Name.
  • Bulk actions: BulkAction::make('bulkEdit')->form(...) (category / purchase price / batch tracking); ->archive() sets items.archived_at; ExportAction runs via the Filament export job (async notification, same pipeline as the import toast); DeleteBulkAction is policy-guarded — deletable only when no stock_movements rows reference the variant, so items with ledger history are skipped (archive instead — GMP immutability). Toolbar Export CSV icon runs the same export over the filtered set when nothing is selected.