diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-06-13 17:19:28 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-06-13 17:19:28 +0700 |
| commit | d2c05ac97f195e196605d91088d6f76d9312e528 (patch) | |
| tree | 6968bce8655a77298efaf36f84169ac5bf9b09e3 | |
| parent | 860abd78b0474279f851378f0b6507fe71fd76be (diff) | |
<miqdad> match with meet
| -rw-r--r-- | indoteknik_custom/models/tukar_guling.py | 141 | ||||
| -rwxr-xr-x | indoteknik_custom/security/ir.model.access.csv | 3 | ||||
| -rw-r--r-- | indoteknik_custom/views/tukar_guling.xml | 149 |
3 files changed, 246 insertions, 47 deletions
diff --git a/indoteknik_custom/models/tukar_guling.py b/indoteknik_custom/models/tukar_guling.py index ca246c7f..e214e268 100644 --- a/indoteknik_custom/models/tukar_guling.py +++ b/indoteknik_custom/models/tukar_guling.py @@ -8,14 +8,145 @@ class TukarGuling(models.Model): _order = 'date desc, id desc' _rec_name = 'name' - # Hanya 2 field seperti yang Anda inginkan - name = fields.Char('Reference', required=True, copy=False, readonly=True, default='New') + name = fields.Char('Number', required=True, copy=False, readonly=True, default='New') date = fields.Datetime('Date', default=fields.Datetime.now, required=True) + out_num = fields.Many2one('stock.picking', 'Nomor BU/Out', required=True, + domain=[('picking_type_id.code', '=', 'outgoing')]) + ba_num = fields.Text('Nomor BA') + notes = fields.Text('Notes') + return_type = fields.Selection(String='Return Type', selection=[ + ('tukar_guling', 'Tukar Guling'), + ('revisi_so', 'Revisi SO'), + ('revisi_po', 'Revisi PO'), + ('credit_memo', 'Credit Memo'), + ('debit_memo', 'Debit Memo'), + ('lain_lain', 'Lain-lain')]) + + # ✅ PERBAIKAN: Ganti 'states' dengan 'state' + state = fields.Selection(string='Status', selection=[ + ('draft', 'Draft'), + ('waiting', 'Waiting for Approval'), + ('done', 'Done'), + ('cancel', 'Canceled') + ], default='draft', tracking=True, required=True) + + # ✅ NEW: Line items + line_ids = fields.One2many('tukar.guling.line', 'tukar_guling_id', string='Product Lines') + + @api.constrains('line_ids', 'state') + def _check_product_lines(self): + """Constraint: Product lines harus ada jika state bukan draft""" + for record in self: + if record.state in ('waiting', 'done') and not record.line_ids: + raise ValidationError("Product lines harus diisi sebelum submit atau approve!") + + def _validate_product_lines(self): + """Helper method untuk validasi product lines""" + self.ensure_one() + + # Check ada product lines + if not self.line_ids: + raise UserError("Belum ada product lines yang ditambahkan!") + + # Check product sudah diisi + empty_lines = self.line_ids.filtered(lambda line: not line.product_id) + if empty_lines: + raise UserError("Ada product lines yang belum diisi productnya!") + + # Check quantity > 0 + zero_qty_lines = self.line_ids.filtered(lambda line: line.product_uom_qty <= 0) + if zero_qty_lines: + raise UserError("Quantity product tidak boleh kosong atau 0!") + + return True - # Sequence generator @api.model_create_multi def create(self, vals_list): for vals in vals_list: if vals.get('name', 'New') == 'New': - vals['name'] = self.env['ir.sequence'].next_by_code('tukar.guling') or '0' - return super(TukarGuling, self).create(vals_list)
\ No newline at end of file + vals['name'] = self.env['ir.sequence'].next_by_code('tukar.guling') or 'PTG/00001' + return super(TukarGuling, self).create(vals_list) + + def copy(self, default=None): + """Override copy untuk custom behavior saat duplicate""" + if default is None: + default = {} + + # Reset fields penting saat duplicate + default.update({ + 'name': 'New', # Akan auto-generate sequence baru + 'state': 'draft', + 'date': fields.Datetime.now(), + # ba_num dan out_num tidak di-reset, user bisa edit manual + }) + + # Copy record dengan default values + new_record = super(TukarGuling, self).copy(default) + + # Re-sequence line items untuk record baru + if new_record.line_ids: + for i, line in enumerate(new_record.line_ids): + line.sequence = (i + 1) * 10 + + return new_record + + def action_draft(self): + """Reset to draft state""" + for record in self: + if record.state == 'cancel': + record.write({'state': 'draft'}) + else: + raise UserError("Hanya record yang di-cancel yang bisa dikembalikan ke draft") + + def action_submit(self): + self.ensure_one() + if self.state != 'draft': + raise UserError("Hanya status Draft saja yang bisa di submit") + self.state = 'waiting' + + def action_approve(self): + self.ensure_one() + if self.state != 'waiting': + raise UserError("Hanya status Waiting saja yang bisa di approve") + self.state = 'done' + + def action_cancel(self): + self.ensure_one() + if self.state == 'done': + raise UserError("Tidak bisa cancel jika sudah done") + self.state = 'cancel' + + +class TukarGulingLine(models.Model): + _name = 'tukar.guling.line' + _description = 'Tukar Guling Line' + _order = 'sequence, id' + + sequence = fields.Integer('Sequence', default=10, copy=False) + tukar_guling_id = fields.Many2one('tukar.guling', string='Tukar Guling', required=True, ondelete='cascade') + product_id = fields.Many2one('product.product', string='Product', required=True) + product_uom_qty = fields.Float('Quantity', digits='Product Unit of Measure', required=True, default=1.0) + product_uom = fields.Many2one('uom.uom', string='Unit of Measure') + name = fields.Text('Description') + + @api.model_create_multi + def create(self, vals_list): + """Override create to auto-assign sequence""" + for vals in vals_list: + if 'sequence' not in vals or vals.get('sequence', 0) <= 0: + # Get max sequence untuk tukar_guling yang sama + tukar_guling_id = vals.get('tukar_guling_id') + if tukar_guling_id: + max_seq = self.search([ + ('tukar_guling_id', '=', tukar_guling_id) + ], order='sequence desc', limit=1) + vals['sequence'] = (max_seq.sequence or 0) + 10 + else: + vals['sequence'] = 10 + return super(TukarGulingLine, self).create(vals_list) + + @api.onchange('product_id') + def _onchange_product_id(self): + if self.product_id: + self.name = self.product_id.display_name + self.product_uom = self.product_id.uom_id
\ No newline at end of file diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 5b60f3ac..26198a0f 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -181,4 +181,5 @@ access_shipping_option,shipping.option,model_shipping_option,,1,1,1,1 access_production_purchase_match,access.production.purchase.match,model_production_purchase_match,,1,1,1,1 access_image_carousel,access.image.carousel,model_image_carousel,,1,1,1,1 access_v_sale_notin_matchpo,access.v.sale.notin.matchpo,model_v_sale_notin_matchpo,,1,1,1,1 -access_tukar_guling_all_users,tukar.guling.all.users,model_tukar_guling,base.group_user,1,1,1,0 +access_tukar_guling_all_users,tukar.guling.all.users,model_tukar_guling,base.group_user,1,1,1,1 +access_tukar_guling_line_all_users,tukar.guling.line.all.users,model_tukar_guling_line,base.group_user,1,1,1,1 diff --git a/indoteknik_custom/views/tukar_guling.xml b/indoteknik_custom/views/tukar_guling.xml index 34f2fa48..8fffcbb0 100644 --- a/indoteknik_custom/views/tukar_guling.xml +++ b/indoteknik_custom/views/tukar_guling.xml @@ -1,50 +1,117 @@ <?xml version="1.0" encoding="UTF-8" ?> <odoo> - <record id="action_pengajuan_tukar_guling" model="ir.actions.act_window"> - <field name="name">Pengajuan Tukar Guling</field> - <field name="type">ir.actions.act_window</field> - <field name="res_model">tukar.guling</field> - <field name="view_mode">tree,form</field> - </record> + <data> + <!-- Action --> + <record id="action_pengajuan_tukar_guling" model="ir.actions.act_window"> + <field name="name">Pengajuan Tukar Guling</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">tukar.guling</field> + <field name="view_mode">tree,form</field> + </record> - <menuitem - id="menu_pengajuan_tukar_guling" - name="Pengajuan Tukar Guling" - parent="stock.menu_warehouse_report" - sequence="3" - action="action_pengajuan_tukar_guling" - /> + <!-- Menu --> + <menuitem + id="menu_pengajuan_tukar_guling" + name="Pengajuan Tukar Guling" + parent="stock.menu_warehouse_report" + sequence="3" + action="action_pengajuan_tukar_guling" + /> - <record id="seq_tukar_guling" model="ir.sequence"> - <field name="name">Pengajuan Tukar Guling</field> - <field name="code">tukar.guling</field> - <field name="prefix">PTG/</field> - <field name="padding">5</field> - <field name="number_next">1</field> - <field name="number_increment">1</field> - <field name="company_id" eval="False"/> - </record> + <!-- Sequence --> + <record id="seq_tukar_guling" model="ir.sequence"> + <field name="name">Pengajuan Tukar Guling</field> + <field name="code">tukar.guling</field> + <field name="prefix">PTG/</field> + <field name="padding">5</field> + <field name="number_next">1</field> + <field name="number_increment">1</field> + <field name="company_id" eval="False"/> + </record> - <record id="pengajuan_tukar_guling_tree" model="ir.ui.view"> - <field name="name">pengajuan.tukar.guling.tree</field> - <field name="model">tukar.guling</field> - <field name="arch" type="xml"> - <tree create="1" default_order="create_date desc"> + <!-- Tree View --> + <record id="pengajuan_tukar_guling_tree" model="ir.ui.view"> + <field name="name">pengajuan.tukar.guling.tree</field> + <field name="model">tukar.guling</field> + <field name="arch" type="xml"> + <tree create="1" delete="1" default_order="create_date desc"> <field name="name"/> <field name="date"/> - </tree> - </field> - </record> + <field name="out_num" string="BU/Out"/> + <field name="ba_num" string="Nomor BA"/> + <field name="return_type" string="Return Type"/> + <field name="state" widget="badge" + decoration-info="state in ('draft', 'waiting')" + decoration-success="state == 'done'" + decoration-muted="state == 'cancel'" + /> + </tree> + </field> + </record> - <record id="pengajuan_tukar_guling_form" model="ir.ui.view"> - <field name="name">pengajuan.tukar.guling.form</field> - <field name="model">tukar.guling</field> - <field name="arch" type="xml"> - <form> - <group> - <field name="name" widget="text"/> - </group> - </form> - </field> - </record> + <!-- Form View --> + <record id="pengajuan_tukar_guling_form" model="ir.ui.view"> + <field name="name">pengajuan.tukar.guling.form</field> + <field name="model">tukar.guling</field> + <field name="arch" type="xml"> + <form> + <header> + <button name="action_submit" string="Submit" type="object" + class="btn-primary" + attrs="{'invisible': [('state', '!=', 'draft')]}"/> + <button name="action_approve" string="Approve" type="object" + class="btn-primary" + attrs="{'invisible': [('state', '!=', 'waiting')]}"/> + <button name="action_cancel" string="Cancel" type="object" + class="btn-secondary" + attrs="{'invisible': [('state', 'in', ('done', 'cancel'))]}" + confirm="Are you sure you want to cancel this record?"/> + <button name="action_draft" string="Set to Draft" type="object" + class="btn-secondary" + attrs="{'invisible': [('state', '!=', 'cancel')]}" + confirm="Are you sure you want to reset this record to draft?"/> + <field name="state" widget="statusbar" + statusbar_visible="draft,waiting,done,cancel"/> + </header> + <sheet> + <div class="oe_title"> + <h1> + <field name="name" readonly="1" class="oe_inline"/> + </h1> + <hr/> + </div> + <group> + <group> + <field name="date" string="Date" readonly="1"/> + <field name="out_num" string="BU/Out"/> + <field name="ba_num" string="Nomor BA"/> + </group> + <group> + <field name="return_type"/> + <field name="notes"/> + <field name="state" readonly="1"/> + </group> + </group> + + <!-- Product Lines --> + <notebook> + <page string="Product Lines" name="product_lines"> + <field name="line_ids"> + <tree string="Product Lines" editable="bottom"> + <field name="sequence" widget="handle"/> + <field name="product_id" required="1" + options="{'no_create': True, 'no_create_edit': True}"/> + <field name="name" force_save="1"/> + <field name="product_uom_qty" string="Quantity"/> + <field name="product_uom" string="UoM" + options="{'no_create': True, 'no_create_edit': True}"/> + </tree> + </field> + </page> + </notebook> + </sheet> + </form> + </field> + </record> + </data> </odoo>
\ No newline at end of file |
