diff options
| -rw-r--r-- | indoteknik_api/controllers/api_v1/product.py | 2 | ||||
| -rw-r--r-- | indoteknik_api/controllers/api_v1/stock_picking.py | 10 | ||||
| -rw-r--r-- | indoteknik_api/models/product_product.py | 5 | ||||
| -rw-r--r-- | indoteknik_api/models/sale_order.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/approval_unreserve.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/automatic_purchase.py | 66 | ||||
| -rw-r--r-- | indoteknik_custom/models/res_partner.py | 25 | ||||
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 31 | ||||
| -rw-r--r-- | indoteknik_custom/models/sale_order_line.py | 7 | ||||
| -rw-r--r-- | indoteknik_custom/models/solr/product_product.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/stock_picking.py | 81 | ||||
| -rw-r--r-- | indoteknik_custom/models/vendor_approval.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/models/wati.py | 57 | ||||
| -rw-r--r-- | indoteknik_custom/models/website_user_cart.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/views/partner_payment_term.xml | 3 | ||||
| -rw-r--r-- | indoteknik_custom/views/res_partner.xml | 11 | ||||
| -rwxr-xr-x | indoteknik_custom/views/sale_order.xml | 41 | ||||
| -rw-r--r-- | indoteknik_custom/views/stock_picking.xml | 1 |
18 files changed, 236 insertions, 114 deletions
diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index b68eb0f9..32362582 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -103,7 +103,7 @@ class Product(controller.Controller): product = request.env['product.product'].search( [('id', '=', id)], limit=1) - qty_available = product.free_qty + qty_available = product.qty_free_bandengan data = { 'qty': qty_available, diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py index ea8c6400..110cde8a 100644 --- a/indoteknik_api/controllers/api_v1/stock_picking.py +++ b/indoteknik_api/controllers/api_v1/stock_picking.py @@ -32,7 +32,9 @@ class StockPicking(controller.Controller): pending_domain = [('driver_departure_date', '=', False), ('driver_arrival_date', '=', False)] shipment_domain = [('driver_departure_date', '!=', False), ('driver_arrival_date', '=', False)] - completed_domain = [('driver_departure_date', '!=', False), ('driver_arrival_date', '!=', False)] + shipment_domain2 = [('driver_departure_date', '!=', False), ('sj_return_date', '=', False)] + completed_domain = [('driver_departure_date', '!=', False),'|', ('driver_arrival_date', '!=', False), ('sj_return_date', '!=', False)] + completed_domain2 = [('driver_departure_date', '!=', False), ('sj_return_date', '!=', False)] picking_model = request.env['stock.picking'] domain = [ @@ -74,7 +76,7 @@ class StockPicking(controller.Controller): 'name': picking.sale_id.name, 'client_order_ref': picking.sale_id.client_order_ref or '' }, - 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False, + 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False or picking.sj_return_date != False, 'status': picking.shipping_status, 'carrier_name': picking.carrier_id.name or '', 'last_manifest': next(iter(manifests), None) @@ -83,8 +85,8 @@ class StockPicking(controller.Controller): return self.response({ 'summary': { 'pending_count': picking_model.search_count(default_domain + pending_domain), - 'shipment_count': picking_model.search_count(default_domain + shipment_domain), - 'completed_count': picking_model.search_count(default_domain + completed_domain) + 'shipment_count': picking_model.search_count(default_domain + shipment_domain + shipment_domain2), + 'completed_count': picking_model.search_count(default_domain + completed_domain ) }, 'picking_total': picking_model.search_count(domain), 'pickings': res_pickings diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index 386ddb6a..f8869c7d 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -61,8 +61,9 @@ class ProductProduct(models.Model): price_for = self.env.context.get('price_for', 'odoo') pricelist = pricelist or self.env.context.get('user_pricelist') default_price_tier = '1_v2' - - price_tier = pricelist.get_tier_level() + price_tier = [] + if pricelist: + price_tier = pricelist.get_tier_level() price_tier = price_tier if price_tier else default_price_tier pricelist = self._get_pricelist_tier(price_tier) diff --git a/indoteknik_api/models/sale_order.py b/indoteknik_api/models/sale_order.py index 8e0371a3..54e1fd40 100644 --- a/indoteknik_api/models/sale_order.py +++ b/indoteknik_api/models/sale_order.py @@ -33,7 +33,7 @@ class SaleOrder(models.Model): 'id': picking.id, 'name': picking.name, 'tracking_number': picking.delivery_tracking_no or '', - 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False, + 'delivered': picking.waybill_id.delivered or picking.driver_arrival_date != False or picking.sj_return_date != False, }) if sale_order.state == 'cancel': data['status'] = 'cancel' diff --git a/indoteknik_custom/models/approval_unreserve.py b/indoteknik_custom/models/approval_unreserve.py index ba8b8da7..d847ea37 100644 --- a/indoteknik_custom/models/approval_unreserve.py +++ b/indoteknik_custom/models/approval_unreserve.py @@ -86,7 +86,7 @@ class ApprovalUnreserve(models.Model): }) # Trigger the unreserve function self._trigger_unreserve() - self.picking_id.check_state_reserve() + # self.picking_id.check_state_reserve() def action_reject(self, reason): if self.env.user.id != self.user_id.id: diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index 548115e6..4e96e6d4 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -401,36 +401,40 @@ class AutomaticPurchase(models.Model): domain = [ ('product_id', '=', line.product_id.id) ] - sale = self.env['v.sales.outstanding'].search(domain, order='sale_order_create_date desc', limit=1) - - existing_match = self.env['automatic.purchase.sales.match'].search([ - ('automatic_purchase_id', '=', self.id), - ('sale_id', '=', sale.sale_id.id), - ('product_id', '=', sale.product_id.id), - ]) + sales = self.env['v.sales.outstanding'].search(domain, order='sale_order_create_date desc') - price_so = self.env['sale.order.line'].search([ - ('id', '=', sale.sale_line_id.id), - ]) - - if existing_match: - continue + for sale in sales: + existing_match = self.env['automatic.purchase.sales.match'].search([ + ('automatic_purchase_id', '=', self.id), + ('sale_id', '=', sale.sale_id.id), + ('sale_line_id', '=', sale.sale_line_id.id), + ('product_id', '=', sale.product_id.id), + ]) - self.env['automatic.purchase.sales.match'].create([{ - 'automatic_purchase_id': self.id, - 'sale_id': sale.sale_id.id, - 'sale_line_id': sale.sale_line_id.id, - 'picking_id': sale.picking_id.id, - 'move_id': sale.move_id.id, - 'partner_id': sale.partner_id.id, - 'partner_invoice_id': sale.partner_invoice_id.id, - 'salesperson_id': sale.salesperson_id.id, - 'product_id': sale.product_id.id, - 'qty_so': sale.outgoing, - 'qty_po': line.qty_purchase, - 'purchase_price': price_so.purchase_price, - 'purchase_tax_id': price_so.purchase_tax_id.id if price_so.purchase_tax_id.id else None, - }]) + # price_so = self.env['sale.order.line'].search([ + # ('id', '=', sale.sale_line_id.id), + # ]) + + if existing_match: + continue + + self.env['automatic.purchase.sales.match'].create([{ + 'automatic_purchase_id': self.id, + 'sale_id': sale.sale_id.id, + 'sale_line_id': sale.sale_line_id.id, + 'picking_id': sale.picking_id.id, + 'move_id': sale.move_id.id, + 'partner_id': sale.partner_id.id, + 'partner_invoice_id': sale.partner_invoice_id.id, + 'salesperson_id': sale.salesperson_id.id, + 'product_id': sale.product_id.id, + 'qty_so': sale.outgoing, + 'qty_po': line.qty_purchase, + 'purchase_price': sale.sale_line_id.purchase_price, + 'purchase_tax_id': sale.sale_line_id.purchase_tax_id.id if sale.sale_line_id.purchase_tax_id.id else None, + # 'purchase_price': price_so.purchase_price, + # 'purchase_tax_id': price_so.purchase_tax_id.id if price_so.purchase_tax_id.id else None, + }]) def _create_sync_purchasing_job(self, jobs): date = datetime.utcnow() @@ -462,9 +466,9 @@ class AutomaticPurchase(models.Model): count = 0 for point in orderpoints: # _logger.info('test %s' % point.product_id.name) - if point.product_id.virtual_available > point.product_min_qty: + if point.product_id.qty_available_bandengan > point.product_min_qty: continue - qty_purchase = point.product_max_qty - point.product_id.virtual_available + qty_purchase = point.product_max_qty - point.product_id.qty_available_bandengan po_line = self.env['purchase.order.line'].search([('product_id', '=', point.product_id.id), ('order_id.state', '=', 'done')], order='id desc', limit=1) if self.vendor_id: @@ -491,7 +495,7 @@ class AutomaticPurchase(models.Model): 'qty_purchase': qty_purchase, 'qty_min': point.product_min_qty, 'qty_max': point.product_max_qty, - 'qty_available': point.product_id.virtual_available, + 'qty_available': point.product_id.qty_available_bandengan, # 'partner_id': po_line.order_id.partner_id.id, # 'last_price': po_line.price_unit, 'partner_id': vendor_id, diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index ec027ec1..9d1b70f8 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -11,6 +11,16 @@ class GroupPartner(models.Model): class ResPartner(models.Model): _inherit = 'res.partner' + property_account_payable_id = fields.Many2one('account.account', company_dependent=True, + string="Account Payable", + domain="[('internal_type', '=', 'payable'), ('deprecated', '=', False), ('company_id', '=', current_company_id)]", + help="This account will be used instead of the default one as the payable account for the current partner", + default=438) + property_account_receivable_id = fields.Many2one('account.account', company_dependent=True, + string="Account Receivable", + domain="[('internal_type', '=', 'receivable'), ('deprecated', '=', False), ('company_id', '=', current_company_id)]", + help="This account will be used instead of the default one as the receivable account for the current partner", + default=395) # Referensi supplier_ids = fields.Many2many('user.pengajuan.tempo.line', string="Suppliers") @@ -85,7 +95,7 @@ class ResPartner(models.Model): counter = fields.Integer(string="Counter", default=0) leadtime = fields.Integer(string="Leadtime", default=0) digital_invoice_tax = fields.Boolean(string="Digital Invoice & Faktur Pajak") - is_potential = fields.Boolean(string='Potential') + is_not_potential = fields.Boolean(string='Not Potential') pakta_integritas = fields.Boolean(string='Pakta Integritas') use_so_approval = fields.Boolean(string='Use SO Approval') @@ -116,6 +126,16 @@ class ResPartner(models.Model): company_type = fields.Selection(string='Company Type', selection=[('person', 'Individual'), ('company', 'Company')], compute='_compute_company_type', inverse='_write_company_type', tracking=3) + warning_stage = fields.Float(string='Warning Amount', + help="A warning message will appear once the " + "selected customer is crossed warning " + "amount. Set its value to 0.00 to" + " disable this feature", tracking=3) + blocking_stage = fields.Float(string='Blocking Amount', + help="Cannot make sales once the selected " + "customer is crossed blocking amount." + "Set its value to 0.00 to disable " + "this feature", tracking=3) @api.model def _default_payment_term(self): @@ -307,8 +327,7 @@ class ResPartner(models.Model): # res = super(ResPartner, self).write(vals) # return res - @api.depends('company_type', 'parent_id', 'npwp', 'sppkp', 'nama_wajib_pajak', 'alamat_lengkap_text', 'industry_id', - 'company_type_id') + @api.depends('company_type', 'parent_id', 'npwp', 'sppkp', 'nama_wajib_pajak','alamat_lengkap_text', 'industry_id', 'company_type_id') def _related_fields(self): for partner in self: if partner.company_type == 'person' and partner.parent_id: diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 75332996..5e868edd 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -626,20 +626,6 @@ class SaleOrder(models.Model): # return ['&', ('order_line.invoice_lines.move_id.move_type', 'in', ('out_invoice', 'out_refund')), ('order_line.invoice_lines.move_id', operator, value)] - # def check_data_real_delivery_address(self): - # real_delivery_address = self.real_shipping_id - - # if not real_delivery_address.state_id: - # raise UserError('State Real Delivery Address harus diisi') - # if not real_delivery_address.zip: - # raise UserError('Zip code Real Delivery Address harus diisi') - # if not real_delivery_address.mobile: - # raise UserError('Mobile Real Delivery Address harus diisi') - # if not real_delivery_address.phone: - # raise UserError('Phone Real Delivery Address harus diisi') - # if not real_delivery_address.kecamatan_id: - # raise UserError('Kecamatan Real Delivery Address harus diisi') - @api.onchange('partner_id') def onchange_partner_contact(self): parent_id = self.partner_id.parent_id @@ -650,6 +636,7 @@ class SaleOrder(models.Model): self.customer_type = parent_id.customer_type self.email = parent_id.email self.pareto_status = parent_id.pareto_status + self.user_id = parent_id.user_id @api.onchange('partner_id') def onchange_partner_id(self): @@ -762,7 +749,7 @@ class SaleOrder(models.Model): raise UserError("Salesperson sudah tidak aktif, mohon diisi yang benar pada data SO dan Contact") def sale_order_approve(self): - if self.validate_different_vendor() and not self.vendor_approval and not self.vendor_approval_id: + if self.validate_different_vendor() and not self.vendor_approval: return self._create_notification_action('Notification', 'Terdapat Vendor yang berbeda dengan MD Vendor') self.check_due() @@ -939,7 +926,7 @@ class SaleOrder(models.Model): def action_confirm(self): for order in self: - if self.validate_different_vendor() and not self.vendor_approval and not self.vendor_approval_id: + if self.validate_different_vendor() and not self.vendor_approval: return self._create_notification_action('Notification', 'Terdapat Vendor yang berbeda dengan MD Vendor') order.check_data_real_delivery_address() @@ -980,6 +967,16 @@ class SaleOrder(models.Model): # order.order_line.get_reserved_from() res = super(SaleOrder, self).action_confirm() + for order in self: + note = [] + for line in order.order_line: + if line.display_type == 'line_note': + note.append(line.name) + + if order.picking_ids: + # Sort picking_ids by creation date to get the most recent one + latest_picking = order.picking_ids.sorted(key=lambda p: p.create_date, reverse=True)[0] + latest_picking.notee = '\n'.join(note) return res def action_cancel(self): @@ -1063,6 +1060,8 @@ class SaleOrder(models.Model): partner.email = self.email if not partner.customer_type: partner.customer_type = self.customer_type + if not partner.user_id: + partner.user_id = self.user_id.id # if not partner.sppkp or not partner.npwp or not partner.email or partner.customer_type: # partner.customer_type = self.customer_type diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 5a6640ec..04fafa69 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -37,6 +37,11 @@ class SaleOrderLine(models.Model): weight = fields.Float(string='Weight') md_vendor_id = fields.Many2one('res.partner', string='MD Vendor', readonly=True) margin_md = fields.Float(string='Margin MD') + qty_free_bu = fields.Float(string='Free BU', compute='_get_qty_free_bandengan') + + def _get_qty_free_bandengan(self): + for line in self: + line.qty_free_bu = line.product_id.qty_free_bandengan @api.constrains('note_procurement') def note_procurement_to_apo(self): @@ -372,5 +377,5 @@ class SaleOrderLine(models.Model): continue if not line.product_id.product_tmpl_id.sale_ok: raise UserError('Product %s belum bisa dijual, harap hubungi finance' % line.product_id.display_name) - if not line.vendor_id or not line.purchase_price: + if not line.vendor_id or not line.purchase_price and not line.display_type == 'line_note': raise UserError(_('Isi Vendor dan Harga Beli sebelum Request Approval'))
\ No newline at end of file diff --git a/indoteknik_custom/models/solr/product_product.py b/indoteknik_custom/models/solr/product_product.py index dd1d40f6..667511b2 100644 --- a/indoteknik_custom/models/solr/product_product.py +++ b/indoteknik_custom/models/solr/product_product.py @@ -54,7 +54,7 @@ class ProductProduct(models.Model): ('location_id', 'in', target_locations), ]) - is_in_bu = any(quant.available_quantity > 0 for quant in stock_quant) + is_in_bu = True if variant.qty_free_bandengan > 0 else False document = solr_model.get_doc('variants', variant.id) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 50e9304b..10b26711 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -34,7 +34,6 @@ class StockPicking(models.Model): ) driver_arrival_date = fields.Datetime( string='Delivery Arrival Date', - readonly=True, copy=False ) delivery_tracking_no = fields.Char( @@ -112,6 +111,7 @@ class StockPicking(models.Model): ('done', 'Done'), ('cancel', 'Cancelled'), ], string='Status Reserve', readonly=True, tracking=True, help="The current state of the stock picking.") + notee = fields.Text(string="Note") def action_send_to_biteship(self): url = "https://api.biteship.com/v1/orders" @@ -193,9 +193,10 @@ class StockPicking(models.Model): else: raise UserError(f"Error saat mengirim ke Biteship: {response.content}") - # @api.constrains('driver_departure_date') - # def constrains_driver_departure_date(self): - # self.date_doc_kirim = self.driver_departure_date + @api.constrains('driver_departure_date') + def constrains_driver_departure_date(self): + if not self.date_doc_kirim: + self.date_doc_kirim = self.driver_departure_date @api.constrains('arrival_time') def constrains_arrival_time(self): @@ -279,9 +280,9 @@ class StockPicking(models.Model): def _compute_shipping_status(self): for rec in self: status = 'pending' - if rec.driver_departure_date and not rec.driver_arrival_date: + if rec.driver_departure_date and not (rec.sj_return_date or rec.driver_arrival_date): status = 'shipment' - elif rec.driver_departure_date and rec.driver_arrival_date: + elif rec.driver_departure_date and (rec.sj_return_date or rec.driver_arrival_date): status = 'completed' rec.shipping_status = status @@ -441,26 +442,31 @@ class StockPicking(models.Model): for pick in self: if self.env.user.is_accounting: pick.approval_return_status = 'approved' - else: - if self.picking_type_code == 'outgoing': - if self.env.user.id in [3988, 3401, 20]: - action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_stock_return_note_wizard') - action['context'] = { - 'picking_ids': [x.id for x in self] - } - return action - else: - raise UserError('Harus Sales Admin yang Ask Return') - elif self.picking_type_code == 'incoming': - if self.env.user.has_group('indoteknik_custom.group_role_purchasing'): - action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_stock_return_note_wizard') - action['context'] = { - 'picking_ids': [x.id for x in self] - } - return action - else: - raise UserError('Harus Purchasing yang Ask Return') + continue + action = self.env['ir.actions.act_window']._for_xml_id('indoteknik_custom.action_stock_return_note_wizard') + + if self.picking_type_code == 'outgoing': + if self.env.user.id in [3988, 3401, 20] or ( + self.env.user.has_group('indoteknik_custom.group_role_purchasing') and 'Return of' in self.origin + ): + action['context'] = {'picking_ids': [x.id for x in self]} + return action + elif not self.env.user.has_group('indoteknik_custom.group_role_purchasing') and 'Return of' in self.origin: + raise UserError('Harus Purchasing yang Ask Return') + else: + raise UserError('Harus Sales Admin yang Ask Return') + + elif self.picking_type_code == 'incoming': + if self.env.user.has_group('indoteknik_custom.group_role_purchasing') or ( + self.env.user.id in [3988, 3401, 20] and 'Return of' in self.origin + ): + action['context'] = {'picking_ids': [x.id for x in self]} + return action + elif not self.env.user.id in [3988, 3401, 20] and 'Return of' in self.origin: + raise UserError('Harus Sales Admin yang Ask Return') + else: + raise UserError('Harus Purchasing yang Ask Return') def calculate_line_no(self): @@ -517,12 +523,31 @@ class StockPicking(models.Model): and quant.inventory_quantity < line.product_uom_qty ): raise UserError('Quantity reserved lebih besar dari quantity onhand di product') + + def check_qty_done_stock(self): + for line in self.move_line_ids_without_package: + def check_qty_per_inventory(self, product, location): + quant = self.env['stock.quant'].search([ + ('product_id', '=', product.id), + ('location_id', '=', location.id), + ]) + if quant: + return quant.quantity + + return 0 + + qty_onhand = check_qty_per_inventory(self, line.product_id, line.location_id) + if line.qty_done > qty_onhand: + raise UserError('Quantity Done melebihi Quantity Onhand') def button_validate(self): if not self.env.user.is_logistic_approver and self.env.context.get('active_model') == 'stock.picking': if self.origin and 'Return of' in self.origin: raise UserError("Button ini hanya untuk Logistik") + + if self.picking_type_code == 'internal': + self.check_qty_done_stock() if self._name != 'stock.picking': return super(StockPicking, self).button_validate() @@ -651,13 +676,13 @@ class StockPicking(models.Model): manifest_datas = [] departure_date = self.driver_departure_date - arrival_date = self.driver_arrival_date + arrival_date = self.sj_return_date if self.sj_return_date else self.driver_arrival_date status = status_mapping.get(status_key) if not status: return manifest_datas - if arrival_date: + if arrival_date or self.sj_return_date: manifest_datas.append(self.create_manifest_data(status['arrival'], arrival_date)) if departure_date: manifest_datas.append(self.create_manifest_data(status['departure'], departure_date)) @@ -684,7 +709,7 @@ class StockPicking(models.Model): } if not self.waybill_id or len(self.waybill_id.manifest_ids) == 0: - response['delivered'] = self.driver_arrival_date != False + response['delivered'] = self.sj_return_date != False or self.driver_arrival_date != False return response response['delivery_order']['receiver_name'] = self.waybill_id.receiver_name diff --git a/indoteknik_custom/models/vendor_approval.py b/indoteknik_custom/models/vendor_approval.py index bcc5d3ea..56b81a37 100644 --- a/indoteknik_custom/models/vendor_approval.py +++ b/indoteknik_custom/models/vendor_approval.py @@ -32,7 +32,7 @@ class VendorApproval(models.Model): self.order_id.vendor_approval = True message = "Vendor Approval approved by %s" % (self.env.user.name) self.order_id.message_post(body=message) - if not self.order_id.due_id: + if not self.order_id.due_id and self.order_id.state == 'draft': self.order_id.action_confirm() def action_reject(self): diff --git a/indoteknik_custom/models/wati.py b/indoteknik_custom/models/wati.py index eed5413e..f3632334 100644 --- a/indoteknik_custom/models/wati.py +++ b/indoteknik_custom/models/wati.py @@ -58,41 +58,56 @@ class WatiNotification(models.Model): return def _create_wati_history_header(self, ticket_id, sender_name, notification_json, date_wati): + # Helper function to remove NUL characters + def remove_null_characters(value): + if isinstance(value, str): + return value.replace('\0', '') + return value + + # Sanitize the input data param_header = { 'ticket_id': ticket_id, - 'conversation_id': notification_json['conversationId'], - 'sender_name': sender_name, - 'wa_id': notification_json['waId'], - 'text': notification_json['text'], - 'date_wati': date_wati or '', + 'conversation_id': remove_null_characters(notification_json.get('conversationId', '')), + 'sender_name': remove_null_characters(sender_name), + 'wa_id': remove_null_characters(notification_json.get('waId', '')), + 'text': remove_null_characters(notification_json.get('text', '')), + 'date_wati': remove_null_characters(date_wati or ''), } + + # Create the record new_header = self.env['wati.history'].create([param_header]) return new_header def _create_wati_history_line(self, new_header, ticket_id, sender_name, notification_json, date_wati): - text_body = notification_json['text'] or '' + # Helper function to remove NUL characters + def remove_null_characters(value): + if isinstance(value, str): + return value.replace('\0', '') + return value + + # Sanitize the input data param_line = { "wati_history_id": new_header.id, - "conversation_id": notification_json['conversationId'], - "data": notification_json['data'] or '', - "event_type": notification_json['eventType'] or '', - # "list_reply": notification_json['listReply'] or '', - # "message_contact": notification_json['messageContact'] or '', - "operator_email": notification_json['operatorEmail'] or '', - "operator_name": notification_json['operatorName'] or '', - "sender_name": sender_name or '', - # "source_url": notification_json['sourceUrl'] or '', - "status_string": notification_json['statusString'] or '', - "text": text_body, + "conversation_id": remove_null_characters(notification_json.get('conversationId', '')), + "data": remove_null_characters(notification_json.get('data', '')), + "event_type": remove_null_characters(notification_json.get('eventType', '')), + "operator_email": remove_null_characters(notification_json.get('operatorEmail', '')), + "operator_name": remove_null_characters(notification_json.get('operatorName', '')), + "sender_name": remove_null_characters(sender_name or ''), + "status_string": remove_null_characters(notification_json.get('statusString', '')), + "text": remove_null_characters(notification_json.get('text', '')), "ticket_id": ticket_id, - "type": notification_json['type'] or '', - "wa_id": notification_json['waId'] or '', - "date_wati": date_wati or '', + "type": remove_null_characters(notification_json.get('type', '')), + "wa_id": remove_null_characters(notification_json.get('waId', '')), + "date_wati": remove_null_characters(date_wati or ''), } + + # Create the record safely without NUL characters self.env['wati.history.line'].create([param_line]) - self._update_header_after_create_line(new_header, sender_name, date_wati, text_body) + self._update_header_after_create_line(new_header, sender_name, date_wati, param_line['text']) return + def _update_header_after_create_line(self, new_header, sender_name, date_wati, text_body): new_header.last_reply_by = sender_name new_header.last_reply_date = date_wati diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index 494f32f3..44393cf1 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -65,7 +65,7 @@ class WebsiteUserCart(models.Model): if stock_quant: res['is_in_bu'] = True res['on_hand_qty'] = sum(stock_quant.mapped('quantity')) - res['available_quantity'] = stock_quant.available_quantity + res['available_quantity'] = sum(stock_quant.mapped('available_quantity')) else: res['is_in_bu'] = False res['on_hand_qty'] = 0 diff --git a/indoteknik_custom/views/partner_payment_term.xml b/indoteknik_custom/views/partner_payment_term.xml index 433cac3e..e0f2fe39 100644 --- a/indoteknik_custom/views/partner_payment_term.xml +++ b/indoteknik_custom/views/partner_payment_term.xml @@ -24,6 +24,9 @@ <field name="name"/> <field name="parent_id" readonly="1"/> <field name="property_payment_term_id"/> + <field name="active_limit"/> + <field name="warning_stage"/> + <field name="blocking_stage"/> </group> </group> </sheet> diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index cc6b2357..6ce340f3 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -6,6 +6,15 @@ <field name="model">res.partner</field> <field name="inherit_id" ref="base.view_partner_form"/> <field name="arch" type="xml"> + <field name="active_limit" position="attributes"> + <attribute name="readonly">1</attribute> + </field> + <field name="warning_stage" position="attributes"> + <attribute name="readonly">1</attribute> + </field> + <field name="blocking_stage" position="attributes"> + <attribute name="readonly">1</attribute> + </field> <field name="npwp" position="after"> <field name="sppkp"/> <field name="counter"/> @@ -22,7 +31,7 @@ <field name="industry_id" position="after"> <field name="company_type_id"/> <field name="group_partner_id"/> - <field name="is_potential"/> + <field name="is_not_potential"/> <field name="pareto_status"/> <field name="digital_invoice_tax"/> </field> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index b8f2d08d..3a3b1c81 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -118,8 +118,47 @@ } </attribute> </xpath> + <div name="invoice_lines" position="before"> + <div name="vendor_id" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}"> + <label for="vendor_id"/> + <div name="vendor_id"> + <field name="vendor_id" + attrs="{'readonly': [('parent.approval_status', '=', 'approved')]}" + domain="[('parent_id', '=', False)]" + options="{'no_create': True}" class="oe_inline" /> + </div> + </div> + </div> + + <div name="invoice_lines" position="before"> + <div name="purchase_price" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}"> + <label for="purchase_price"/> + <field name="purchase_price"/> + </div> + </div> + <div name="invoice_lines" position="before"> + <div name="purchase_tax_id" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}"> + <label for="purchase_tax_id"/> + <div name="purchase_tax_id"> + <field name="purchase_tax_id"/> + </div> + </div> + </div> + <div name="invoice_lines" position="before"> + <div name="item_percent_margin" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}"> + <label for="item_percent_margin"/> + <field name="item_percent_margin"/> + </div> + </div> + <div name="invoice_lines" position="before"> + <div name="price_subtotal" groups="base.group_no_one" attrs="{'invisible': [('display_type', '!=', False)]}"> + <label for="price_subtotal"/> + <field name="price_subtotal"/> + </div> + </div> <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_total']" position="after"> - <field name="vendor_id" attrs="{'readonly': [('parent.approval_status', '=', 'approved')]}" domain="[('parent_id', '=', False)]" options="{'no_create':True}"/> + <field name="qty_free_bu" optional="hide"/> + <field name="vendor_id" attrs="{'readonly': [('parent.approval_status', '=', 'approved')], 'invisible': [('display_type', '!=', False)]}" domain="[('parent_id', '=', False)]" options="{'no_create':True}"/> <field name="vendor_md_id" optional="hide"/> <field name="purchase_price" attrs=" { diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index c230bc7b..1893fcaf 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -129,6 +129,7 @@ <page string="Delivery" name="delivery_order"> <group> <group> + <field name="notee"/> <field name="note_logistic"/> <field name="responsible" /> <field name="carrier_id"/> |
