From f4f55acddc7d5b071289095b139614acce35308c Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 19 Aug 2025 09:23:53 +0700 Subject: trying to fix bug solr --- indoteknik_custom/models/solr/product_template.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py index c4aefe19..e362626b 100644 --- a/indoteknik_custom/models/solr/product_template.py +++ b/indoteknik_custom/models/solr/product_template.py @@ -121,12 +121,11 @@ class ProductTemplate(models.Model): "category_name": category_names, # Nama kategori sebagai list "description_t": template.website_description or '', "description_clean_t": cleaned_desc or '', - 'has_product_info_b': True, - 'publish_b': not template.unpublished, - 'sni_b': template.sni, - 'tkdn_b': template.tkdn, - "qty_sold_f": template.qty_sold, - "is_in_bu_b": is_in_bu, + 'has_product_info_b': self.bool_to_solr(True), + 'publish_b': self.bool_to_solr(not template.unpublished), + 'sni_b': self.bool_to_solr(template.sni), + 'tkdn_b': self.bool_to_solr(template.tkdn), + "is_in_bu_b": self.bool_to_solr(is_in_bu), "voucher_min_purchase_f" : voucher.min_purchase_amount or 0, "voucher_discount_type_s" : voucher.discount_type or '', "voucher_discount_amount_f" : voucher.discount_amount or 0, @@ -143,6 +142,10 @@ class ProductTemplate(models.Model): if not document.get('has_price_info_b'): template._sync_price_to_solr() + + def bool_to_solr(val): + return 'true' if val else 'false' + def get_category_hierarchy_ids(self, category_id): """ -- cgit v1.2.3 From 1e4cd196b7b41a38ee5f974667c421ae53c8e52f Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 19 Aug 2025 09:30:43 +0700 Subject: add logger --- indoteknik_custom/models/solr/product_template.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py index e362626b..b1c6654b 100644 --- a/indoteknik_custom/models/solr/product_template.py +++ b/indoteknik_custom/models/solr/product_template.py @@ -2,6 +2,9 @@ from datetime import datetime from bs4 import BeautifulSoup from odoo import api, fields, models +import logging + +_logger = logging.getLogger(__name__) class ProductTemplate(models.Model): @@ -132,6 +135,8 @@ class ProductTemplate(models.Model): "voucher_max_discount_f" : voucher.max_discount_amount or 0 }) + _logger.info(document) + self.solr().add(docs=[document], softCommit=True) products = self.env['product.product'].search([ ('product_tmpl_id', '=', template.id), -- cgit v1.2.3 From fd15be6548fa56ecf7df4fb44ab469eb9b4b4dc9 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 19 Aug 2025 10:32:24 +0700 Subject: fix bug --- indoteknik_custom/models/solr/product_template.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py index b1c6654b..c4aefe19 100644 --- a/indoteknik_custom/models/solr/product_template.py +++ b/indoteknik_custom/models/solr/product_template.py @@ -2,9 +2,6 @@ from datetime import datetime from bs4 import BeautifulSoup from odoo import api, fields, models -import logging - -_logger = logging.getLogger(__name__) class ProductTemplate(models.Model): @@ -124,19 +121,18 @@ class ProductTemplate(models.Model): "category_name": category_names, # Nama kategori sebagai list "description_t": template.website_description or '', "description_clean_t": cleaned_desc or '', - 'has_product_info_b': self.bool_to_solr(True), - 'publish_b': self.bool_to_solr(not template.unpublished), - 'sni_b': self.bool_to_solr(template.sni), - 'tkdn_b': self.bool_to_solr(template.tkdn), - "is_in_bu_b": self.bool_to_solr(is_in_bu), + 'has_product_info_b': True, + 'publish_b': not template.unpublished, + 'sni_b': template.sni, + 'tkdn_b': template.tkdn, + "qty_sold_f": template.qty_sold, + "is_in_bu_b": is_in_bu, "voucher_min_purchase_f" : voucher.min_purchase_amount or 0, "voucher_discount_type_s" : voucher.discount_type or '', "voucher_discount_amount_f" : voucher.discount_amount or 0, "voucher_max_discount_f" : voucher.max_discount_amount or 0 }) - _logger.info(document) - self.solr().add(docs=[document], softCommit=True) products = self.env['product.product'].search([ ('product_tmpl_id', '=', template.id), @@ -147,10 +143,6 @@ class ProductTemplate(models.Model): if not document.get('has_price_info_b'): template._sync_price_to_solr() - - def bool_to_solr(val): - return 'true' if val else 'false' - def get_category_hierarchy_ids(self, category_id): """ -- cgit v1.2.3 From 0d29ad7c92fbbf9c0f2a17502a7cc39e6c4df1ec Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Tue, 19 Aug 2025 10:59:04 +0700 Subject: fix --- indoteknik_custom/models/stock_picking.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index d63c5d4c..cb36eb2f 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -19,10 +19,10 @@ import re _logger = logging.getLogger(__name__) _biteship_url = "https://api.biteship.com/v1" -# biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" +biteship_api_key = "biteship_live.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiaW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTc0MTE1NTU4M30.pbFCai9QJv8iWhgdosf8ScVmEeP3e5blrn33CHe7Hgo" -biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" +# biteship_api_key = "biteship_test.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSW5kb3Rla25payIsInVzZXJJZCI6IjY3MTViYTJkYzVkMjdkMDAxMjRjODk2MiIsImlhdCI6MTcyOTQ5ODAwMX0.L6C73couP4-cgVEfhKI2g7eMCMo3YOFSRZhS-KSuHNA" class StockPicking(models.Model): -- cgit v1.2.3 From e2d186dd98b2c0d1bc9bab8ea9b7d80c59873046 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 19 Aug 2025 14:02:45 +0700 Subject: add percent pie on sale order --- indoteknik_custom/models/sale_order.py | 41 +++++++++++++++++++++++++++++ indoteknik_custom/models/sale_order_line.py | 27 +++++++++++++++++++ indoteknik_custom/views/sale_order.xml | 6 +++++ 3 files changed, 74 insertions(+) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 0acfa0b0..80790ebe 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -376,6 +376,47 @@ class SaleOrder(models.Model): compute='_compute_advance_payment_moves', store=False ) + reserved_percent = fields.Float( + string="Reserved %", digits=(16, 2), + compute="_compute_reserved_delivered_pie", store=False + ) + delivered_percent = fields.Float( + string="Delivered %", digits=(16, 2), + compute="_compute_reserved_delivered_pie", store=False + ) + unreserved_percent = fields.Float( + string="Unreserved %", digits=(16, 2), + compute="_compute_reserved_delivered_pie", store=False + ) + + @api.depends('order_line.reserved_percent', 'order_line.delivered_percent', 'order_line.unreserved_percent') + def _compute_reserved_delivered_pie(self): + for order in self: + total_qty = sum(order.order_line.mapped('product_uom_qty')) + reserved_qty = delivered_qty = 0.0 + + if total_qty > 0: + for line in order.order_line: + order_qty = line.product_uom_qty or 0.0 + if not order_qty: + continue + + # ambil qty asli dari move, bukan percent agar akurat + pick_moves = line.move_ids.filtered( + lambda m: m.picking_type_id.code == 'internal' and m.state not in ('done', 'cancel') + ) + reserved_qty += sum(pick_moves.mapped('reserved_availability')) + + out_moves = line.move_ids.filtered( + lambda m: m.picking_type_id.code == 'outgoing' and m.state == 'done' + ) + delivered_qty += sum(out_moves.mapped('quantity_done')) + + order.reserved_percent = (reserved_qty / total_qty) * 100 + order.delivered_percent = (delivered_qty / total_qty) * 100 + order.unreserved_percent = 100 - order.reserved_percent - order.delivered_percent + else: + order.reserved_percent = order.delivered_percent = order.unreserved_percent = 0 def _has_ccm(self): if self.id: diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 64b9f9bc..2a00bac0 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -54,6 +54,33 @@ class SaleOrderLine(models.Model): desc_updatable = fields.Boolean(string='desc boolean', default=True, compute='_get_desc_updatable') is_has_disc = fields.Boolean('Flash Sale', default=False) + reserved_percent = fields.Float(string="Reserved %", digits=(16, 2), compute="_compute_reserved_delivered_pie", store=False) + delivered_percent = fields.Float(string="Delivered %", digits=(16, 2), compute="_compute_reserved_delivered_pie", store=False) + unreserved_percent = fields.Float(string="Unreserved %", digits=(16, 2), compute="_compute_reserved_delivered_pie", store=False) + + @api.depends('move_ids') + def _compute_reserved_delivered_pie(self): + for line in self: + order_qty = line.product_uom_qty or 0.0 + reserved_qty = delivered_qty = 0.0 + + if order_qty > 0: + # Reserved: hanya dari BU/PICK yang masih aktif + pick_moves = line.move_ids.filtered( + lambda m: m.picking_type_id.code == 'internal' and m.state not in ('done', 'cancel') + ) + reserved_qty = sum(pick_moves.mapped('reserved_availability')) + + # Delivered: hanya dari BU/OUT yang sudah done + out_moves = line.move_ids.filtered( + lambda m: m.picking_type_id.code == 'outgoing' and m.state == 'done' + ) + delivered_qty = sum(out_moves.mapped('quantity_done')) + + line.reserved_percent = (reserved_qty / order_qty) * 100 if order_qty else 0 + line.delivered_percent = (delivered_qty / order_qty) * 100 if order_qty else 0 + line.unreserved_percent = 100 - line.reserved_percent - line.delivered_percent + def _get_outgoing_incoming_moves(self): diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 868bce7b..518bc9d6 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -290,6 +290,9 @@ + + + @@ -461,6 +464,9 @@ + + + -- cgit v1.2.3 From c225119cb9bdcee03ca9706ec58dfceb717b5027 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Tue, 19 Aug 2025 14:42:27 +0700 Subject: fix percentpie --- indoteknik_custom/views/sale_order.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 518bc9d6..5fad5700 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -464,9 +464,9 @@ + - @@ -483,6 +483,9 @@ + + + -- cgit v1.2.3 From dde108ba7e3690b0ef655fe7449814e9021bab74 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Wed, 20 Aug 2025 09:58:00 +0700 Subject: (andri) add field janji bayar & button sync ke inv customer dengan due date yang sama --- indoteknik_custom/models/account_move.py | 48 +++++++++++++++++++++++++++++++- indoteknik_custom/views/account_move.xml | 7 +++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index b0ffd8b9..3a07cf87 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -99,6 +99,12 @@ class AccountMove(models.Model): reminder_sent_date = fields.Date(string="Tanggal Reminder Terkirim") + customer_promise_date = fields.Date( + string="Janji Bayar", + help="Tanggal janji bayar dari customer setelah reminder dikirim.", + tracking=True + ) + def compute_partial_payment(self): for move in self: if move.amount_total_signed > 0 and move.amount_residual_signed > 0 and move.payment_state == 'partial': @@ -121,6 +127,46 @@ class AccountMove(models.Model): else: move.payment_date = False + def action_sync_promise_date(self): + for inv in self: + if not inv.customer_promise_date: + inv.env.user.notify_warning( + message="Isi Janji Bayar terlebih dahulu sebelum melakukan sinkronisasi.", + title="Sync Gagal", + ) + continue + + # Cari invoice lain milik partner yang due date sama + other_invoices = self.search([ + ('id', '!=', inv.id), + ('partner_id', '=', inv.partner_id.id), + ('invoice_date_due', '=', inv.invoice_date_due), + ('move_type', '=', 'out_invoice'), + ('state', '=', 'posted'), + ]) + + if not other_invoices: + inv.env.user.notify_info( + message="Tidak ada invoice lain dengan due date yang sama untuk disinkronkan.", + title="Sync Janji Bayar", + ) + continue + + # Sync field + other_invoices.write({'customer_promise_date': inv.customer_promise_date}) + + # Log di invoices lain + for other in other_invoices: + other.message_post( + body=f"Janji Bayar {inv.customer_promise_date} disinkronkan dari invoice {inv.name}." + ) + + # Log di invoice asal + other_names = ", ".join(other_invoices.mapped("name")) + inv.message_post( + body=f"Janji Bayar {inv.customer_promise_date} disinkronkan ke {len(other_invoices)} invoice lain: {other_names}." + ) + def send_due_invoice_reminder(self): today = fields.Date.today() @@ -279,7 +325,7 @@ class AccountMove(models.Model): } _logger.info(f"Mengirim email ke: {values['email_to']} > email CC: {values['email_cc']}") - template.send_mail(invs[0].id, force_send=True, email_values=values) + # template.send_mail(invs[0].id, force_send=True, email_values=values) # flag invs.write({'reminder_sent_date': today}) # Post ke chatter diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index e5d1cf8a..284043d0 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -68,6 +68,13 @@ + + + +