diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-11-11 13:35:02 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-11-11 13:35:02 +0700 |
| commit | 4c69c892f7b8ef7ec0877023f3f9544c8e9eb42c (patch) | |
| tree | 038e771e90339517d64a933175d87cc48c3c7f72 | |
| parent | 062c606f4c31ee0966a6c08f4f3de52d719df883 (diff) | |
| parent | 0373d7545ec889d8cdfee6d09bb93123df5a60cb (diff) | |
<Miqdad> merge
| -rw-r--r-- | indoteknik_custom/models/advance_payment_request.py | 4 | ||||
| -rw-r--r-- | indoteknik_custom/models/automatic_purchase.py | 3 | ||||
| -rw-r--r-- | indoteknik_custom/models/commision.py | 4 | ||||
| -rw-r--r-- | indoteknik_custom/models/coretax_fatur.py | 4 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 52 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_move.py | 26 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 60 | ||||
| -rw-r--r-- | indoteknik_custom/report/purchase_report.xml | 2 | ||||
| -rwxr-xr-x | indoteknik_custom/views/sale_order.xml | 1 | ||||
| -rw-r--r-- | indoteknik_custom/views/stock_picking.xml | 14 |
10 files changed, 136 insertions, 34 deletions
diff --git a/indoteknik_custom/models/advance_payment_request.py b/indoteknik_custom/models/advance_payment_request.py index a3a3d20a..6ea1c160 100644 --- a/indoteknik_custom/models/advance_payment_request.py +++ b/indoteknik_custom/models/advance_payment_request.py @@ -846,9 +846,9 @@ class AdvancePaymentUsageLine(models.Model): attachment_filename_pdf = fields.Char(string='Filename PDF') account_id = fields.Many2one( - 'account.account', string='Jenis Biaya', tracking=3, - domain="[('id', 'in', [484, 486, 488, 506, 507, 625, 471, 519, 527, 528, 529, 530, 565])]" # ID Jenis Biaya yang dibutuhkan + 'account.account', string='Jenis Biaya', tracking=3 # ID Jenis Biaya yang dibutuhkan ) + # domain="[('id', 'in', [484, 486, 488, 506, 507, 625, 471, 519, 527, 528, 529, 530, 565])]" # ID Jenis Biaya yang dibutuhkan is_current_user_ap = fields.Boolean( string="Is Current User AP", diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index ce0328c4..4b0ce325 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -284,7 +284,8 @@ class AutomaticPurchase(models.Model): 'ending_price': line.last_price, 'taxes_id': [(6, 0, [line.taxes_id.id])] if line.taxes_id else False, 'so_line_id': sales_match.sale_line_id.id if sales_match else None, - 'so_id': sales_match.sale_id.id if sales_match else None + 'so_id': sales_match.sale_id.id if sales_match else None, + 'show_description': False if vendor_id == 5571 else True, } new_po_line = self.env['purchase.order.line'].create(param_line) line.current_po_id = new_po.id diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py index a937e2d0..441dd54f 100644 --- a/indoteknik_custom/models/commision.py +++ b/indoteknik_custom/models/commision.py @@ -423,8 +423,8 @@ class CustomerCommision(models.Model): def action_confirm_customer_commision(self): jakarta_tz = pytz.timezone('Asia/Jakarta') now = datetime.now(jakarta_tz) - - now_naive = now.replace(tzinfo=None) + now_utc = now.astimezone(pytz.utc) + now_naive = now_utc.replace(tzinfo=None) if not self.status or self.status == 'draft': self.status = 'pengajuan1' diff --git a/indoteknik_custom/models/coretax_fatur.py b/indoteknik_custom/models/coretax_fatur.py index ce94306f..7e0de919 100644 --- a/indoteknik_custom/models/coretax_fatur.py +++ b/indoteknik_custom/models/coretax_fatur.py @@ -147,6 +147,8 @@ class CoretaxFaktur(models.Model): subtotal = line_price_subtotal quantity = line_quantity total_discount = round(line_discount, 2) + coretax_id = line.product_uom_id.coretax_id + uom_name = line.product_uom_id.name # Calculate other tax values otherTaxBase = round(subtotal * (11 / 12), 2) if subtotal else 0 @@ -159,7 +161,7 @@ class CoretaxFaktur(models.Model): ET.SubElement(good_service, 'Opt').text = 'A' ET.SubElement(good_service, 'Code').text = '000000' ET.SubElement(good_service, 'Name').text = line_name - ET.SubElement(good_service, 'Unit').text = 'UM.0018' + ET.SubElement(good_service, uom_name).text = coretax_id # ET.SubElement(good_service, 'Price').text = str(round(line_price_unit, 2)) if line_price_unit else '0' ET.SubElement(good_service, 'Price').text = str(price_per_unit) ET.SubElement(good_service, 'Qty').text = str(quantity) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 1d07a1ff..357d2395 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -398,6 +398,45 @@ class SaleOrder(models.Model): compute="_compute_partner_is_cbd_locked" ) internal_notes_contact = fields.Text(related='partner_id.comment', string="Internal Notes", readonly=True, help="Internal Notes dari contact utama customer.") + is_so_fiktif = fields.Boolean('SO Fiktif?') + + def action_set_shipping_id(self): + for rec in self: + bu_pick = self.env['stock.picking'].search([ + ('state', 'not in', ['cancel']), + ('picking_type_id', '=', 30), + ('sale_id', '=', rec.id), + ('linked_manual_bu_out', '=', False) + ]) + # bu_out = bu_pick_has_out.mapped('linked_manual_bu_out') + bu_out = self.env['stock.picking'].search([ + ('sale_id', '=', rec.id), + ('picking_type_id', '=', 29), + ('state', 'not in', ['cancel', 'done']) + ]) + bu_pick_has_out = self.env['stock.picking'].search([ + ('state', 'not in', ['cancel']), + ('picking_type_id', '=', 30), + ('sale_id', '=', rec.id), + ('linked_manual_bu_out.id', '=', bu_out.id), + ('linked_manual_bu_out.state', 'not in', ['done', 'cancel']) + ]) + for pick in bu_pick_has_out: + linked_out = pick.linked_manual_bu_out + if pick.real_shipping_id != rec.real_shipping_id or linked_out.partner_id != rec.partner_shipping_id: + pick.real_shipping_id = rec.real_shipping_id + pick.partner_id = rec.partner_shipping_id + linked_out.partner_id = rec.partner_shipping_id + linked_out.real_shipping_id = rec.real_shipping_id + _logger.info('Updated bu_pick [%s] and bu_out [%s]', pick.name, linked_out.name) + + for pick in bu_pick: + if pick.real_shipping_id != rec.real_shipping_id: + pick.real_shipping_id = rec.real_shipping_id + pick.partner_id = rec.partner_shipping_id + bu_out.partner_id = rec.partner_shipping_id + bu_out.real_shipping_id = rec.real_shipping_id + _logger.info('Updated bu_pick [%s] without bu_out', pick.name) def action_open_partial_delivery_wizard(self): # raise UserError("Fitur ini sedang dalam pengembangan") @@ -2278,7 +2317,7 @@ class SaleOrder(models.Model): raise UserError("Terdapat DUPLIKASI data pada Product {}".format(line.product_id.display_name)) def sale_order_approve(self): - # self.check_duplicate_product() + self.check_duplicate_product() self.check_product_bom() self.check_credit_limit() self.check_limit_so_to_invoice() @@ -2356,6 +2395,7 @@ class SaleOrder(models.Model): self.check_credit_limit() self.check_limit_so_to_invoice() order.approval_status = 'pengajuan1' + order.message_post(body="Mengajukan approval ke Team Sales") return self._create_approval_notification('Team Sales') if not order.with_context(ask_approval=True)._is_request_to_own_team_leader(): @@ -2549,7 +2589,7 @@ class SaleOrder(models.Model): for order in self: order._validate_delivery_amt() order._validate_uniform_taxes() - # order.check_duplicate_product() + order.check_duplicate_product() order.check_product_bom() order.check_credit_limit() order.check_limit_so_to_invoice() @@ -2598,6 +2638,7 @@ class SaleOrder(models.Model): return self._create_approval_notification('Sales Manager') elif order._requires_approval_team_sales(): order.approval_status = 'pengajuan1' + order.message_post(body="Mengajukan approval ke Team Sales") return self._create_approval_notification('Team Sales') order.approval_status = 'approved' @@ -2703,8 +2744,8 @@ class SaleOrder(models.Model): def _requires_approval_team_sales(self): return ( - # 18 <= self.total_percent_margin <= 24 - self.total_percent_margin >= 18 + 18 <= self.total_percent_margin <= 24 + # self.total_percent_margin >= 18 and self.env.user.id not in [11, 9, 375] # Eko, Ade, Putra and not self.env.user.is_sales_manager and not self.env.user.is_leader @@ -3376,6 +3417,9 @@ class SaleOrder(models.Model): # if updated_vals: # line.write(updated_vals) + + if 'real_shipping_id' in vals: + self.action_set_shipping_id() return res def button_refund(self): diff --git a/indoteknik_custom/models/stock_move.py b/indoteknik_custom/models/stock_move.py index 38cf0199..cac88287 100644 --- a/indoteknik_custom/models/stock_move.py +++ b/indoteknik_custom/models/stock_move.py @@ -22,12 +22,12 @@ class StockMove(models.Model): partial = fields.Boolean('Partial?', default=False) # Ambil product uom dari SO line - # @api.model - # def create(self, vals): - # if vals.get('sale_line_id'): - # sale_line = self.env['sale.order.line'].browse(vals['sale_line_id']) - # vals['product_uom'] = sale_line.product_uom.id - # return super().create(vals) + @api.model + def create(self, vals): + if vals.get('sale_line_id'): + sale_line = self.env['sale.order.line'].browse(vals['sale_line_id']) + vals['product_uom'] = sale_line.product_uom.id + return super().create(vals) # @api.model_create_multi # def create(self, vals_list): @@ -282,10 +282,10 @@ class StockMoveLine(models.Model): picking.delivery_status = 'none' # Ambil uom dari stock move - # @api.model - # def create(self, vals): - # if 'move_id' in vals and 'product_uom_id' not in vals: - # move = self.env['stock.move'].browse(vals['move_id']) - # if move.product_uom: - # vals['product_uom_id'] = move.product_uom.id - # return super().create(vals)
\ No newline at end of file + @api.model + def create(self, vals): + if 'move_id' in vals and 'product_uom_id' not in vals: + move = self.env['stock.move'].browse(vals['move_id']) + if move.product_uom: + vals['product_uom_id'] = move.product_uom.id + return super().create(vals)
\ No newline at end of file diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 04847be8..49001974 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -5,16 +5,16 @@ from collections import defaultdict from datetime import timedelta, datetime from datetime import timedelta, datetime as waktu from itertools import groupby -import pytz, requests, json, requests +import pytz, json from dateutil import parser import datetime import hmac import hashlib -import base64 import requests import time import logging import re +import base64 _logger = logging.getLogger(__name__) @@ -200,6 +200,13 @@ class StockPicking(models.Model): ('full', 'Full'), ], string='Delivery Status', compute='_compute_delivery_status_detail', store=False) so_num = fields.Char('SO Number', compute='_get_so_num') + is_so_fiktif = fields.Boolean('SO Fiktif?', compute='_compute_is_so_fiktif') + + @api.depends('sale_id.is_so_fiktif') + def _compute_is_so_fiktif(self): + for picking in self: + picking.is_so_fiktif = picking.sale_id.is_so_fiktif if picking.sale_id else False + @api.depends('group_id') def _get_so_num(self): @@ -816,6 +823,37 @@ class StockPicking(models.Model): picking.envio_cod_value = data.get("cod_value", 0.0) picking.envio_cod_status = data.get("cod_status") + images_data = data.get('images', []) + for img in images_data: + image_url = img.get('image') + if image_url: + try: + # Download image from URL + img_response = requests.get(image_url) + img_response.raise_for_status() + + # Encode image to base64 + image_base64 = base64.b64encode(img_response.content) + + # Create attachment in Odoo + attachment = self.env['ir.attachment'].create({ + 'name': 'Envio Image', + 'type': 'binary', + 'datas': image_base64, + 'res_model': picking._name, + 'res_id': picking.id, + 'mimetype': 'image/png', + }) + + # Post log note with attachment + picking.message_post( + body="Image Envio", + attachment_ids=[attachment.id] + ) + + except Exception as e: + picking.message_post(body=f"Gagal ambil image Envio: {str(e)}") + # Menyimpan log terbaru logs = data.get("logs", []) if logs and isinstance(logs, list) and logs[0]: @@ -1378,6 +1416,8 @@ class StockPicking(models.Model): group_id = self.env.ref('indoteknik_custom.group_role_merchandiser').id users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])]) active_model = self.env.context.get('active_model') + if self.is_so_fiktif == True: + raise UserError("SO Fiktif tidak bisa di validate") if self.location_id.id == 47 and self.env.user.id not in users_in_group.mapped( 'id') and self.state_approve_md != 'done': self.state_approve_md = 'waiting' if self.state_approve_md != 'pending' else 'pending' @@ -1416,6 +1456,9 @@ class StockPicking(models.Model): if len(self.check_product_lines) == 0 and 'BU/PICK/' in self.name: raise UserError(_("Tidak ada Check Product! Harap periksa kembali.")) + if len(self.check_product_lines) == 0 and 'BU/INPUT/' in self.name: + raise UserError(_("Tidak ada Check Product! Harap periksa kembali.")) + if self.total_koli > self.total_so_koli: raise UserError(_("Total Koli (%s) dan Total SO Koli (%s) tidak sama! Harap periksa kembali.") % (self.total_koli, self.t1otal_so_koli)) @@ -1559,6 +1602,10 @@ class StockPicking(models.Model): elif self.tukar_guling_po_id: self.tukar_guling_po_id.update_doc_state() + user = self.env.user + if not user.has_group('indoteknik_custom.group_role_logistic'): + raise UserWarning('Validate hnaya bisa di lakukan oleh logistik') + return res def automatic_reserve_product(self): @@ -1729,6 +1776,15 @@ class StockPicking(models.Model): 'indoteknik_custom.group_role_logistic') and self.picking_type_code == 'outgoing': raise UserError("Button ini hanya untuk Logistik") + if len(self.check_product_lines) >= 1: + raise UserError("Tidak Bisa cancel karena sudah di check product") + + if not self.env.user.is_logistic_approver and not self.env.user.has_group('indoteknik_custom.group_role_logistic'): + for picking in self: + if picking.name and ('BU/PICK' in picking.name or 'BU/OUT' in picking.name or 'BU/ORT' in picking.name or 'BU/SRT' in picking.name): + if picking.state not in ['cancel']: + raise UserError("Button ini hanya untuk Logistik") + res = super(StockPicking, self).action_cancel() return res diff --git a/indoteknik_custom/report/purchase_report.xml b/indoteknik_custom/report/purchase_report.xml index 9c0c3983..208e6472 100644 --- a/indoteknik_custom/report/purchase_report.xml +++ b/indoteknik_custom/report/purchase_report.xml @@ -131,7 +131,7 @@ </tr> <!-- WEBSITE DESCRIPTION --> - <t t-if="line.show_description"> + <t t-if="line.show_description == True"> <tr t-attf-style="background-color: #{ '#fef5f5' if line_index % 2 == 0 else '#fffafa' }; "> <td colspan="6" style="padding: 10px 14px; font-size:10px; line-height:1.3; font-style:italic; color:#555; border-left:1px solid #ccc; border-right:1px solid #ccc; border-bottom:1px solid #ccc;"> <div t-raw="line.product_id.website_description"/> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index a540caa7..b2ecc21c 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -130,6 +130,7 @@ </field> <field name="approval_status" position="after"> <field name="notes"/> + <field name="is_so_fiktif"/> </field> <field name="source_id" position="attributes"> <attribute name="invisible">1</attribute> diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index 2925cf2c..4779c5d3 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -147,7 +147,7 @@ <attribute name="attrs">{'readonly': [('parent.picking_type_code', '=', 'incoming')]}</attribute> </field> --> <field name="date_done" position="after"> - <field name="arrival_time"/> + <field name="arrival_time" attrs="{'invisible': [('picking_type_id', 'in', [29,30])]}"/> </field> <field name="scheduled_date" position="attributes"> <attribute name="readonly">1</attribute> @@ -162,11 +162,12 @@ <field name="origin" position="after"> <!-- <field name="show_state_approve_md" invisible="1" optional="hide"/>--> - <field name="state_approve_md" widget="badge"/> + <field name="state_approve_md" widget="badge" attrs="{'invisible': [('picking_type_id', 'in', [29,30])]}"/> <field name="purchase_id"/> <field name="sale_order"/> <field name="invoice_status"/> - <field name="is_bu_iu"/> + <field name="is_bu_iu" /> + <field name="is_so_fiktif" readonly="1"/> <field name="approval_status" attrs="{'invisible': [('is_bu_iu', '=', False)]}"/> <field name="date_doc_kirim" attrs="{'readonly':[('invoice_status', '=', 'invoiced')]}"/> <field name="summary_qty_operation"/> @@ -412,8 +413,7 @@ <field name="qty_yang_mau_dikirim"/> <field name="qty_terkirim"/> <field name="qty_gantung"/> - <field name="delivery_status" widget="badge" - options="{'colors': {'full': 'success', 'partial': 'warning', 'partial_final': 'danger'}}"/> + <field name="delivery_status" widget="badge" options="{'colors': {'full': 'success', 'partial': 'warning', 'partial_final': 'danger'}}"/> </tree> </field> </record> @@ -437,9 +437,7 @@ <form string="Peringatan Koli Belum Diperiksa"> <sheet> <div class="oe_title"> - <h2> - <span>⚠️ Perhatian!</span> - </h2> + <h2><span>⚠️ Perhatian!</span></h2> </div> <group> <field name="message" readonly="1" nolabel="1" widget="text"/> |
