# Custom Product Code & Item Code Automation ## Overview Odoo 17/19 Community tidak punya field `code` standar untuk product category. Untuk kebutuhan stock keeping unit (SKU) yang unik, kita buat field `item_code` yang di‑generate otomatis dari: ``` item_code = parent_category_code (2 digit) + category_code (2 digit) + product_id (4 digit) + name_slug (lowercase, no space) ``` Contoh: - Kategori anak: id=06, parent=01 → prefix = `0106` - Produk: id=3, nama="Backup BRT 30 x 36 x 1,25 mm" - Hasil: `01060003backupbrt30x36x1,25mm` ## Implementation Steps ### 1. Extend `product.category` → field `code` ```python class ProductCategory(models.Model): _inherit = 'product.category' code = fields.Char(string='Category Code', compute='_compute_code', store=True, size=4) @api.model_create_multi def create(self, vals_list): records = super().create(vals_list) for r in records: r.code = f'{r.id:02d}' return records ``` ### 2. Extend `product.template` → field `item_code` Field `item_code`: - **Stored** (`store=True`) — dipakai untuk pencarian & unique index. - **Read‑only di view** — tidak boleh ditulis manual. - **On‑change preview** → tampilkan prefix kategori saat buat produk baru. ```python class ProductTemplate(models.Model): _inherit = 'product.template' item_code = fields.Char(string='Item Code', store=True, readonly=False) _sql_constraints = [ ('item_code_unique', 'UNIQUE(item_code)', 'Item Code harus unik.'), ] @api.model_create_multi def create(self, vals_list): records = super().create(vals_list) for r in records: r.item_code = r._full_item_code(r) return records def write(self, vals): res = super().write(vals) if 'name' in vals or 'categ_id' in vals: for r in self: r.item_code = r._full_item_code(r) return res ``` ### 3. Extend `product.product` (varian) Untuk produk ber‑varian, `item_code` diturunkan via related field ke template: ```python class ProductProduct(models.Model): _inherit = 'product.product' item_code = fields.Char( string='Item Code', related='product_tmpl_id.item_code', store=True, readonly=True, ) ``` ### 4. XML View — field read‑only ```xml ``` ### 5. PostgreSQL — Unique Index (optional, backup) Constraint `__sql_constraints` sudah menambah unique index via Odoo ORM. Untuk kecepatan lebih cepat di PostgreSQL level, dapat manual: ```sql CREATE UNIQUE INDEX IF NOT EXISTS product_template_item_code_uniq ON product_template (item_code) WHERE item_code IS NOT NULL; ``` ### 6. Migration — isi data existing ```python env.cr.execute(""" CREATE UNIQUE INDEX IF NOT EXISTS product_template_item_code_uniq ON product_template (item_code) WHERE item_code IS NOT NULL """) cats = env['product.category'].search([]) for c in cats: if not c.code: c.code = f'{c.id:02d}' prods = env['product.template'].search([]) for p in prods: p.item_code = p._full_item_code(p) ``` ## Pitfalls - `@api.depends('id')` **not allowed** di Odoo 19. Namun `id` tersedia di `create()` setelah super() selesai. - Field `code` di kategori **harus `size` ditentukan** ( Odoo 17+ lint error tanpa `size`) - Product dengan `categ_id = False` → gunakan fallback `00`. - **Item Code read‑only di view**: bila pakai `store=True`, field tetap dapat ditulis via ORM (API). Untuk mencegah manual edit, gunakan `readonly=True` + `@api.constrains` untuk validasi. ## References - `models/product_template.py` — contoh implementasi lengkap (sudah ada di addon `kosbar_erp_ext`) - `views/product_views.xml` — XML view inheritance