This commit is contained in:
2026-09-11 07:00:39 +07:00
parent 85c0a9bb63
commit 4456e5b043
28 changed files with 37 additions and 5 deletions

View File

@@ -0,0 +1,118 @@
# 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
<!-- product_template_form_view inheritance -->
<field name="default_code" position="after">
<field name="item_code" readonly="1" placeholder="Terisi otomatis"/>
</field>
```
### 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