From 043ce9731360bdaffdacc7ee8188ec33ce649d96 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Wed, 13 Aug 2025 09:14:43 +0700 Subject: (andri) fix API User --- indoteknik_api/controllers/api_v1/user.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index b5b7e055..3cfad141 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -396,7 +396,7 @@ class User(controller.Controller): 'user': request.env['res.users'].api_single_response(user) }) - @http.route(prefix + 'user/', auth='public', methods=['PUT', 'OPTIONS'], csrf=False) + @http.route(prefix + 'user/', auth='public', methods=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() def update_user(self, **kw): id = kw.get('id') @@ -446,7 +446,7 @@ class User(controller.Controller): return self.response(address) - @http.route(prefix + 'user//switch', auth='public', methods=['PUT', 'OPTIONS'], csrf=False) + @http.route(prefix + 'user//switch', auth='public', methods=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() def switch_account(self, **kw): id = int(kw.get('id')) -- cgit v1.2.3 From 48acecc8e8b1f77b9b9ea7d71e3d0ff72bed1f3f Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Wed, 13 Aug 2025 13:23:50 +0700 Subject: (andri) fix --- indoteknik_api/controllers/api_v1/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index 3cfad141..50ea8c98 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -489,7 +489,7 @@ class User(controller.Controller): if type_acc == 'business': parameter = [ - ('company_type', '=', 'company'), + ('is_company', '=', True), ('name', 'ilike', business_name) ] if parent_id: -- cgit v1.2.3 From b5a88d98b019c5a561864e56b8d73aaec4f4896a Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Wed, 13 Aug 2025 14:06:54 +0700 Subject: (andri) try fix user company request via switchaccount --- indoteknik_api/controllers/api_v1/user.py | 5 ++--- indoteknik_custom/models/user_company_request.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index 50ea8c98..9044e69c 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -691,11 +691,10 @@ class User(controller.Controller): new_company_request = request.env['user.company.request'].search(parameter, limit=1) is_approve = '' if new_company_request: - # Mengambil nilai is_approve - if new_company_request.is_approve == False: + if not new_company_request.is_approve: # None atau '' response['status'] = 'pending' else: - response['status'] = new_company_request.is_approve + response['status'] = new_company_request.is_approve # 'approved' atau 'rejected' else: response['status'] = False return self.response(response) diff --git a/indoteknik_custom/models/user_company_request.py b/indoteknik_custom/models/user_company_request.py index 9216e8eb..2261545f 100644 --- a/indoteknik_custom/models/user_company_request.py +++ b/indoteknik_custom/models/user_company_request.py @@ -1,6 +1,9 @@ from odoo import models, fields, api from odoo.exceptions import UserError from odoo.http import request +import logging + +_logger = logging.getLogger(__name__) class UserCompanyRequest(models.Model): _name = 'user.company.request' @@ -65,8 +68,8 @@ class UserCompanyRequest(models.Model): is_approve = vals.get('is_approve') is_internal_input = vals.get('internal_input') is_company_id = vals.get('user_company_id') - if self.is_approve and is_approve: - raise UserError('Tidak dapat mengubah approval yang sudah diisi') + # if self.is_approve and is_approve: + # raise UserError('Tidak dapat mengubah approval yang sudah diisi') if is_internal_input: if self.user_company_id.nama_wajib_pajak == self.user_company_id.name: @@ -75,6 +78,7 @@ class UserCompanyRequest(models.Model): user_company_id = [] if is_company_id: user_company_id = request.env['res.partner'].search([('id', '=', is_company_id)], limit=1) + _logger.info('User Company ID: %s', user_company_id) # self.user_company_id.customer_type = self.similar_company_ids.customer_type # self.user_company_id.npwp = self.similar_company_ids.npwp # self.user_company_id.sppkp = self.similar_company_ids.sppkp @@ -101,6 +105,8 @@ class UserCompanyRequest(models.Model): self.user_id.property_account_payable_id = user_company_id.property_account_payable_id if user_company_id else self.user_company_id.property_account_payable_id self.user_id.property_payment_term_id = user_company_id.property_payment_term_id if user_company_id else self.user_company_id.property_payment_term_id self.user_id.property_supplier_payment_term_id = user_company_id.property_supplier_payment_term_id if user_company_id else self.user_company_id.property_supplier_payment_term_id + self.user_id.is_company = True + self.user_id.active = True self.user_company_id.active = True user.send_company_switch_approve_mail() if vals.get('is_switch_account') == True else user.send_company_request_approve_mail() else: -- cgit v1.2.3 From c920de946ec9e942ea98d5f46b8c20fe6c5d9f63 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Thu, 14 Aug 2025 13:53:19 +0700 Subject: (andri) fix isparent user --- indoteknik_custom/models/user_company_request.py | 45 ++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/indoteknik_custom/models/user_company_request.py b/indoteknik_custom/models/user_company_request.py index 2261545f..0c192239 100644 --- a/indoteknik_custom/models/user_company_request.py +++ b/indoteknik_custom/models/user_company_request.py @@ -75,7 +75,7 @@ class UserCompanyRequest(models.Model): if self.user_company_id.nama_wajib_pajak == self.user_company_id.name: self.user_company_id.nama_wajib_pajak = is_internal_input self.user_company_id.name = is_internal_input - user_company_id = [] + user_company_id = request.env['res.partner'] if is_company_id: user_company_id = request.env['res.partner'].search([('id', '=', is_company_id)], limit=1) _logger.info('User Company ID: %s', user_company_id) @@ -92,23 +92,32 @@ class UserCompanyRequest(models.Model): if not self.is_approve and is_approve: if is_approve == 'approved': - self.user_id.parent_id = user_company_id if user_company_id else self.user_company_id - self.user_id.customer_type = user_company_id.customer_type if user_company_id else self.user_company_id.customer_type - self.user_id.npwp = user_company_id.npwp if user_company_id else self.user_company_id.npwp - self.user_id.sppkp = user_company_id.sppkp if user_company_id else self.user_company_id.sppkp - self.user_id.nama_wajib_pajak = user_company_id.nama_wajib_pajak if user_company_id else self.user_company_id.nama_wajib_pajak - self.user_id.alamat_lengkap_text = user_company_id.alamat_lengkap_text if user_company_id else self.user_company_id.alamat_lengkap_text - self.user_id.industry_id = user_company_id.industry_id.id if user_company_id else self.user_company_id.industry_id - self.user_id.company_type_id = user_company_id.company_type_id.id if user_company_id else self.user_company_id.company_type_id - self.user_id.user_id = user_company_id.user_id if user_company_id else self.user_company_id.user_id - self.user_id.property_account_receivable_id = user_company_id.property_account_receivable_id if user_company_id else self.user_company_id.property_account_receivable_id - self.user_id.property_account_payable_id = user_company_id.property_account_payable_id if user_company_id else self.user_company_id.property_account_payable_id - self.user_id.property_payment_term_id = user_company_id.property_payment_term_id if user_company_id else self.user_company_id.property_payment_term_id - self.user_id.property_supplier_payment_term_id = user_company_id.property_supplier_payment_term_id if user_company_id else self.user_company_id.property_supplier_payment_term_id - self.user_id.is_company = True - self.user_id.active = True - self.user_company_id.active = True - user.send_company_switch_approve_mail() if vals.get('is_switch_account') == True else user.send_company_request_approve_mail() + company_rec = user_company_id if user_company_id else self.user_company_id + _logger.info('Company Record: %s', company_rec) + if not company_rec: + raise UserError("Company record tidak ditemukan untuk set parent_id.") + + self.user_id.parent_id = company_rec.id + self.user_id.customer_type = company_rec.customer_type + self.user_id.npwp = company_rec.npwp + self.user_id.sppkp = company_rec.sppkp + self.user_id.nama_wajib_pajak = company_rec.nama_wajib_pajak + self.user_id.alamat_lengkap_text = company_rec.alamat_lengkap_text + self.user_id.industry_id = company_rec.industry_id.id if company_rec.industry_id else False + self.user_id.company_type_id = company_rec.company_type_id.id if company_rec.company_type_id else False + self.user_id.user_id = company_rec.user_id + self.user_id.property_account_receivable_id = company_rec.property_account_receivable_id + self.user_id.property_account_payable_id = company_rec.property_account_payable_id + self.user_id.property_payment_term_id = company_rec.property_payment_term_id + self.user_id.property_supplier_payment_term_id = company_rec.property_supplier_payment_term_id + # self.user_id.is_company = True + self.user_id.active = True + company_rec.active = True + + if vals.get('is_switch_account') is True: + user.send_company_switch_approve_mail() + else: + user.send_company_request_approve_mail() else: # new_company = self.env['res.partner'].create({ # 'name': self.user_input -- cgit v1.2.3 From 33d3124e1283778cfb957c7bb75afc6619c4dd7d Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Thu, 14 Aug 2025 15:11:00 +0700 Subject: (andri) fix --- indoteknik_custom/models/user_company_request.py | 45 ++++++++++-------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/indoteknik_custom/models/user_company_request.py b/indoteknik_custom/models/user_company_request.py index 0c192239..2261545f 100644 --- a/indoteknik_custom/models/user_company_request.py +++ b/indoteknik_custom/models/user_company_request.py @@ -75,7 +75,7 @@ class UserCompanyRequest(models.Model): if self.user_company_id.nama_wajib_pajak == self.user_company_id.name: self.user_company_id.nama_wajib_pajak = is_internal_input self.user_company_id.name = is_internal_input - user_company_id = request.env['res.partner'] + user_company_id = [] if is_company_id: user_company_id = request.env['res.partner'].search([('id', '=', is_company_id)], limit=1) _logger.info('User Company ID: %s', user_company_id) @@ -92,32 +92,23 @@ class UserCompanyRequest(models.Model): if not self.is_approve and is_approve: if is_approve == 'approved': - company_rec = user_company_id if user_company_id else self.user_company_id - _logger.info('Company Record: %s', company_rec) - if not company_rec: - raise UserError("Company record tidak ditemukan untuk set parent_id.") - - self.user_id.parent_id = company_rec.id - self.user_id.customer_type = company_rec.customer_type - self.user_id.npwp = company_rec.npwp - self.user_id.sppkp = company_rec.sppkp - self.user_id.nama_wajib_pajak = company_rec.nama_wajib_pajak - self.user_id.alamat_lengkap_text = company_rec.alamat_lengkap_text - self.user_id.industry_id = company_rec.industry_id.id if company_rec.industry_id else False - self.user_id.company_type_id = company_rec.company_type_id.id if company_rec.company_type_id else False - self.user_id.user_id = company_rec.user_id - self.user_id.property_account_receivable_id = company_rec.property_account_receivable_id - self.user_id.property_account_payable_id = company_rec.property_account_payable_id - self.user_id.property_payment_term_id = company_rec.property_payment_term_id - self.user_id.property_supplier_payment_term_id = company_rec.property_supplier_payment_term_id - # self.user_id.is_company = True - self.user_id.active = True - company_rec.active = True - - if vals.get('is_switch_account') is True: - user.send_company_switch_approve_mail() - else: - user.send_company_request_approve_mail() + self.user_id.parent_id = user_company_id if user_company_id else self.user_company_id + self.user_id.customer_type = user_company_id.customer_type if user_company_id else self.user_company_id.customer_type + self.user_id.npwp = user_company_id.npwp if user_company_id else self.user_company_id.npwp + self.user_id.sppkp = user_company_id.sppkp if user_company_id else self.user_company_id.sppkp + self.user_id.nama_wajib_pajak = user_company_id.nama_wajib_pajak if user_company_id else self.user_company_id.nama_wajib_pajak + self.user_id.alamat_lengkap_text = user_company_id.alamat_lengkap_text if user_company_id else self.user_company_id.alamat_lengkap_text + self.user_id.industry_id = user_company_id.industry_id.id if user_company_id else self.user_company_id.industry_id + self.user_id.company_type_id = user_company_id.company_type_id.id if user_company_id else self.user_company_id.company_type_id + self.user_id.user_id = user_company_id.user_id if user_company_id else self.user_company_id.user_id + self.user_id.property_account_receivable_id = user_company_id.property_account_receivable_id if user_company_id else self.user_company_id.property_account_receivable_id + self.user_id.property_account_payable_id = user_company_id.property_account_payable_id if user_company_id else self.user_company_id.property_account_payable_id + self.user_id.property_payment_term_id = user_company_id.property_payment_term_id if user_company_id else self.user_company_id.property_payment_term_id + self.user_id.property_supplier_payment_term_id = user_company_id.property_supplier_payment_term_id if user_company_id else self.user_company_id.property_supplier_payment_term_id + self.user_id.is_company = True + self.user_id.active = True + self.user_company_id.active = True + user.send_company_switch_approve_mail() if vals.get('is_switch_account') == True else user.send_company_request_approve_mail() else: # new_company = self.env['res.partner'].create({ # 'name': self.user_input -- cgit v1.2.3 From aef7941fa025879bfa47ad626c0de7cb716e2ccc Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 15 Aug 2025 09:08:22 +0700 Subject: fix bug --- indoteknik_custom/models/stock_picking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index bf6834d0..d63c5d4c 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1060,7 +1060,7 @@ class StockPicking(models.Model): self.sale_id.date_doc_kirim = self.date_doc_kirim def action_assign(self): - if self.env.context.get('default_picking_type_id') and self.sale_id: + if self.env.context.get('default_picking_type_id') and ('BU/INPUT' not in self.name or 'BU/PUT' not in self.name): pickings_to_assign = self.filtered( lambda p: not (p.sale_id and p.sale_id.hold_outgoing) ) -- cgit v1.2.3 From 8dd70f877c68abb3f0331e18f4652acb11e1bf84 Mon Sep 17 00:00:00 2001 From: Azka Nathan Date: Fri, 15 Aug 2025 10:42:48 +0700 Subject: partial check product bom --- indoteknik_custom/models/mrp_production.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/indoteknik_custom/models/mrp_production.py b/indoteknik_custom/models/mrp_production.py index 91da0597..b39995b5 100644 --- a/indoteknik_custom/models/mrp_production.py +++ b/indoteknik_custom/models/mrp_production.py @@ -263,7 +263,7 @@ class CheckBomProduct(models.Model): "The product '%s' tidak ada di operations. " ) % record.product_id.display_name) - total_qty_in_moves = sum(moves.mapped('product_uom_qty')) + total_qty_in_moves = sum(moves.mapped('quantity_done')) # Find existing lines for the same product, excluding the current line existing_lines = record.production_id.check_bom_product_lines.filtered( @@ -273,15 +273,15 @@ class CheckBomProduct(models.Model): if existing_lines: total_quantity = sum(existing_lines.mapped('quantity')) - if total_quantity > total_qty_in_moves: + if total_quantity != total_qty_in_moves: raise UserError(( - "Quantity Product '%s' kurang dari quantity demand." + "Quantity Product '%s' harus sama dengan quantity consumed." ) % (record.product_id.display_name)) else: # Check if the quantity exceeds the allowed total - if record.quantity > total_qty_in_moves: + if record.quantity != total_qty_in_moves: raise UserError(( - "Quantity Product '%s' kurang dari quantity demand." + "Quantity Product '%s' harus sama dengan quantity consumed." ) % (record.product_id.display_name)) # Set the quantity to the entered value @@ -446,7 +446,7 @@ class CheckBomProduct(models.Model): "The product '%s' tidak ada di operations. " ) % record.product_id.display_name) - total_qty_in_moves = sum(moves.mapped('product_uom_qty')) + total_qty_in_moves = sum(moves.mapped('quantity_done')) # Find existing lines for the same product, excluding the current line existing_lines = record.production_id.check_bom_product_lines.filtered( @@ -462,13 +462,13 @@ class CheckBomProduct(models.Model): if total_quantity > total_qty_in_moves: raise UserError(( - "Quantity Product '%s' sudah melebihi quantity demand." + "Quantity Product '%s' sudah melebihi quantity consumed." ) % (record.product_id.display_name)) else: # Check if the quantity exceeds the allowed total if record.quantity == total_qty_in_moves: raise UserError(( - "Quantity Product '%s' sudah melebihi quantity demand." + "Quantity Product '%s' sudah melebihi quantity consumed." ) % (record.product_id.display_name)) # Set the quantity to the entered value -- cgit v1.2.3 From c9111bcf2c71a5dac6f13dc5aceb55956127a055 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Fri, 15 Aug 2025 13:59:36 +0700 Subject: (andri) fix --- indoteknik_api/controllers/api_v1/user.py | 16 +++++++++++++++- indoteknik_custom/models/user_company_request.py | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index 9044e69c..d134fc5a 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -674,7 +674,7 @@ class User(controller.Controller): # request_company.send_company_request_mail_switch() request_company.send_company_request_mail_switch() - response['switch'] = 'Pending' + response['switch'] = 'pending' return self.response(response) @http.route(prefix + 'user//switch_progres', auth='public', methods=['GET', 'OPTIONS'], csrf=False) @@ -699,6 +699,20 @@ class User(controller.Controller): response['status'] = False return self.response(response) + # @http.route(prefix + 'user//parent_status', auth='public', methods=['GET', 'OPTIONS'], csrf=False) + # # @controller.Controller.must_authorized() + # def parent_status(self, **kw): + # id = int(kw.get('id')) + # response = { + # 'parentId': None, + # 'parentName': None + # } + # partner = request.env['res.partner'].sudo().search([('id', '=', id)], limit=1) + # if partner and partner.parent_id: + # response['parentId'] = partner.parent_id.id + # response['parentName'] = partner.parent_id.name + # return self.response(response) + def get_user_by_email(self, email): return request.env['res.users'].search([ ('login', '=', email), diff --git a/indoteknik_custom/models/user_company_request.py b/indoteknik_custom/models/user_company_request.py index 2261545f..284575aa 100644 --- a/indoteknik_custom/models/user_company_request.py +++ b/indoteknik_custom/models/user_company_request.py @@ -105,8 +105,8 @@ class UserCompanyRequest(models.Model): self.user_id.property_account_payable_id = user_company_id.property_account_payable_id if user_company_id else self.user_company_id.property_account_payable_id self.user_id.property_payment_term_id = user_company_id.property_payment_term_id if user_company_id else self.user_company_id.property_payment_term_id self.user_id.property_supplier_payment_term_id = user_company_id.property_supplier_payment_term_id if user_company_id else self.user_company_id.property_supplier_payment_term_id - self.user_id.is_company = True - self.user_id.active = True + # self.user_id.is_company = True + # self.user_id.active = True self.user_company_id.active = True user.send_company_switch_approve_mail() if vals.get('is_switch_account') == True else user.send_company_request_approve_mail() else: -- cgit v1.2.3 From b6da6f96857b87f6433c9550085d86adf9319d08 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Fri, 15 Aug 2025 18:04:51 +0700 Subject: (andri) fix api --- indoteknik_api/controllers/api_v1/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index b5b7e055..1d35e01f 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -678,7 +678,7 @@ class User(controller.Controller): return self.response(response) @http.route(prefix + 'user//switch_progres', auth='public', methods=['GET', 'OPTIONS'], csrf=False) - # @controller.Controller.must_authorized() + @controller.Controller.must_authorized() def switch_account_progres(self, **kw): id = int(kw.get('id')) # user = request.env['res.partner'].search([('id', '=', id)], limit=1) -- cgit v1.2.3 From e534cd541152921e9f041176ab18b86172367fa9 Mon Sep 17 00:00:00 2001 From: Miqdad Date: Sat, 16 Aug 2025 13:01:54 +0700 Subject: Partner Map API --- indoteknik_api/controllers/api_v1/partner.py | 69 +++++++----- indoteknik_custom/models/res_partner.py | 151 +++++++++++++++++++++------ 2 files changed, 163 insertions(+), 57 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/partner.py b/indoteknik_api/controllers/api_v1/partner.py index acec19f7..b1d8d5f3 100644 --- a/indoteknik_api/controllers/api_v1/partner.py +++ b/indoteknik_api/controllers/api_v1/partner.py @@ -65,44 +65,61 @@ class Partner(controller.Controller): @controller.Controller.must_authorized() def write_partner_address_by_id(self, id, **kw): headers = { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', - 'Access-Control-Allow-Headers': '*' - } + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': '*' + } if request.httprequest.method == 'OPTIONS': return Response(status=200, headers=headers) + try: params = self.get_request_params(request.jsonrequest, { - 'id': ['required', 'number'], - 'type': ['default:other'], - 'name': ['required'], - 'email': ['required'], - 'mobile': ['required'], - 'phone': [''], - 'street': ['required'], - 'state_id': ['required', 'alias:state_id'], - 'city_id': ['required', 'alias:kota_id'], - 'district_id': ['alias:kecamatan_id'], - 'sub_district_id': ['alias:kelurahan_id', 'exclude_if_null'], - 'zip': ['required'], - 'longtitude': '', - 'latitude': '', - 'address_map': [], - 'alamat_lengkap_text': [] - }) + 'id': ['required', 'number'], + 'type': ['default:other'], + 'name': ['required'], + 'email': ['required'], + 'mobile': ['required'], + 'phone': [''], + 'street': ['required'], + 'state_id': ['required', 'alias:state_id'], + 'city_id': ['required', 'alias:kota_id'], + 'district_id': ['alias:kecamatan_id'], + 'sub_district_id': ['alias:kelurahan_id', 'exclude_if_null'], + 'zip': ['required'], + 'longtitude': '', + 'latitude': '', + 'address_map': [], + + 'alamat_lengkap_text': [] + }) if not params['valid']: - return {'headers' : headers,'code': 400, 'description': params} + return {'headers': headers, 'code': 400, 'description': params} partner = request.env['res.partner'].sudo().search([('id', '=', id)], limit=1) if not partner: - return {'headers' : headers,'code': 404, 'description': 'User not found'} + return {'headers': headers, 'code': 404, 'description': 'User not found'} + vals = dict(params['value']) + vals.pop('id', None) + use_pin = bool(request.jsonrequest.get('use_pin')) + + if not use_pin: + vals.pop('address_map', None) + vals.pop('latitude', None) + vals.pop('longtitude', None) + else: + lat = vals.get('latitude') + lng = vals.get('longtitude') + if not lat or not lng or float(lat) == 0.0 or float(lng) == 0.0: + vals.pop('latitude', None) + vals.pop('longtitude', None) + + partner.write(vals) - partner.write(params['value']) - return {'id': partner.id, 'headers' : headers} + return {'id': partner.id, 'headers': headers} except Exception as e: - return {'headers' : headers,'code': 500, 'description': f'Internal Error: {str(e)}'} + return {'headers': headers, 'code': 500, 'description': f'Internal Error: {str(e)}'} @http.route(prefix + 'partner/address', auth='public', methods=['POST', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized() diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index cf9fbea4..e5e382a1 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -199,16 +199,20 @@ class ResPartner(models.Model): alamat_lengkap_text = fields.Text(string="Alamat Lengkap", required=False, tracking=3) - def write(self, vals): - res = super(ResPartner, self).write(vals) + # def write(self, vals): + # res = super(ResPartner, self).write(vals) - for rec in self: - if 'latitude' in vals or 'longtitude' in vals: - rec._update_address_from_coords() + # use_pin = bool(self.env.context.get('use_pin')) - # Sinkronisasi payment_difficulty ke semua anak jika partner ini adalah parent - if not rec.parent_id and 'payment_difficulty' in vals: - rec.child_ids.write({'payment_difficulty': vals['payment_difficulty']}) + # for rec in self: + # if use_pin and 'latitude' in vals or 'longtitude' in vals: + # # rec._update_address_from_coords() + # rec.with_context(overwrite_street_from_pin=False)._update_address_from_coords() + + + # # Sinkronisasi payment_difficulty ke semua anak jika partner ini adalah parent + # if not rec.parent_id and 'payment_difficulty' in vals: + # rec.child_ids.write({'payment_difficulty': vals['payment_difficulty']}) # # # if 'property_payment_term_id' in vals: # # if not self.env.user.is_accounting and vals['property_payment_term_id'] != 26: @@ -219,17 +223,47 @@ class ResPartner(models.Model): # # if self.env.user.id not in users_in_group.mapped('id'): # # raise UserError('You name it') # + def write(self, vals): + res = super(ResPartner, self).write(vals) + + use_pin = bool(self.env.context.get('use_pin')) + for rec in self: + # Hanya jalan kalau explicit use_pin DAN ada lat/lng di payload + if use_pin and (('latitude' in vals) or ('longtitude' in vals)): + # optional guard: pastikan bukan kosong/0 + lat = rec.latitude + lng = rec.longtitude + if lat and lng and str(lat) not in ('0', '0.0') and str(lng) not in ('0', '0.0'): + rec.with_context(overwrite_street_from_pin=False)._update_address_from_coords() + + # Sinkronisasi payment_difficulty ke anak + if not rec.parent_id and 'payment_difficulty' in vals: + rec.child_ids.write({'payment_difficulty': vals['payment_difficulty']}) return res + + # @api.model + # def create(self, vals): + # records = super().create(vals) + # use_pin = bool(self.env.context.get('use_pin')) + # for rec in records: + # if use_pin and vals.get('latitude') and vals.get('longtitude'): + # rec._update_address_from_coords() + # if rec.parent_id and not vals.get('payment_difficulty'): + # rec.payment_difficulty = rec.parent_id.payment_difficulty + # return records + @api.model def create(self, vals): records = super().create(vals) + use_pin = bool(self.env.context.get('use_pin')) for rec in records: - if vals.get('latitude') and vals.get('longtitude'): - rec._update_address_from_coords() + if use_pin and vals.get('latitude') and vals.get('longtitude'): + rec.with_context(overwrite_street_from_pin=False)._update_address_from_coords() if rec.parent_id and not vals.get('payment_difficulty'): - rec.payment_difficulty = rec.parent_id.payment_difficulty + rec.payment_difficulty = rec.parent_id.payment_difficulty return records + @api.constrains('email') def _check_duplicate_name(self): @@ -621,6 +655,44 @@ class ResPartner(models.Model): else: raise UserError("Permintaan ke Google Maps gagal. Periksa koneksi internet atau API Key.") + # def _update_address_from_coords(self): + # for rec in self: + # if rec.latitude and rec.longtitude: + # try: + # components, formatted, parsed = rec._reverse_geocode(rec.latitude, rec.longtitude) + # if not parsed: + # continue + + # updates = { + # 'street': parsed.get('road') or '', + # 'zip': parsed.get('postcode') or '', + # 'address_map': formatted or '', + # } + + # if self.env.context.get('overwrite_street_from_pin', False): + # updates['street'] = parsed.get('road') or rec.street + + # state = self.env['res.country.state'].search([('name', 'ilike', parsed.get('state'))], limit=1) + # if state: + # updates['state_id'] = state.id + + # kota = self.env['vit.kota'].search([('name', 'ilike', parsed.get('city'))], limit=1) + # if kota: + # updates['kota_id'] = kota.id + + # kec = self.env['vit.kecamatan'].search([('name', 'ilike', parsed.get('district'))], limit=1) + # if kec: + # updates['kecamatan_id'] = kec.id + + # kel = self.env['vit.kelurahan'].search([('name', 'ilike', parsed.get('suburb'))], limit=1) + # if kel: + # updates['kelurahan_id'] = kel.id + + # rec.update(updates) + + # except Exception as e: + # raise UserError(f"Gagal update alamat dari koordinat: {str(e)}") + def _update_address_from_coords(self): for rec in self: if rec.latitude and rec.longtitude: @@ -630,28 +702,45 @@ class ResPartner(models.Model): continue updates = { - 'street': parsed.get('road') or '', - 'zip': parsed.get('postcode') or '', - 'address_map': formatted or '', + 'address_map': formatted or rec.address_map or '', } - state = self.env['res.country.state'].search([('name', 'ilike', parsed.get('state'))], limit=1) - if state: - updates['state_id'] = state.id - - kota = self.env['vit.kota'].search([('name', 'ilike', parsed.get('city'))], limit=1) - if kota: - updates['kota_id'] = kota.id - - kec = self.env['vit.kecamatan'].search([('name', 'ilike', parsed.get('district'))], limit=1) - if kec: - updates['kecamatan_id'] = kec.id - - kel = self.env['vit.kelurahan'].search([('name', 'ilike', parsed.get('suburb'))], limit=1) - if kel: - updates['kelurahan_id'] = kel.id - - rec.update(updates) + # ❌ Jangan isi street kecuali diminta eksplisit via context + if self.env.context.get('overwrite_street_from_pin', False): + road = parsed.get('road') + if road: + updates['street'] = road + + # (Opsional) admin area & zip hanya jika kosong agar tidak menimpa input user + if (not rec.zip) and parsed.get('postcode'): + updates['zip'] = parsed.get('postcode') + + state_name = parsed.get('state') + if state_name and not rec.state_id: + state = self.env['res.country.state'].search([('name', 'ilike', state_name)], limit=1) + if state: + updates['state_id'] = state.id + + city_name = parsed.get('city') + if city_name and not rec.kota_id: + kota = self.env['vit.kota'].search([('name', 'ilike', city_name)], limit=1) + if kota: + updates['kota_id'] = kota.id + + dist_name = parsed.get('district') + if dist_name and not rec.kecamatan_id: + kec = self.env['vit.kecamatan'].search([('name', 'ilike', dist_name)], limit=1) + if kec: + updates['kecamatan_id'] = kec.id + + sub_name = parsed.get('suburb') + if sub_name and not rec.kelurahan_id: + kel = self.env['vit.kelurahan'].search([('name', 'ilike', sub_name)], limit=1) + if kel: + updates['kelurahan_id'] = kel.id + + if updates: + rec.update(updates) except Exception as e: raise UserError(f"Gagal update alamat dari koordinat: {str(e)}") -- cgit v1.2.3 From fc1527eda174b290dee393abec15574cf1bac780 Mon Sep 17 00:00:00 2001 From: "Indoteknik ." Date: Sat, 16 Aug 2025 14:52:40 +0700 Subject: fix --- indoteknik_api/controllers/api_v1/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index 28ac8a5e..dde30fec 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -677,7 +677,7 @@ class User(controller.Controller): response['switch'] = 'pending' return self.response(response) - @http.route(prefix + 'user//switch_progres', auth='public', methods=['GET', 'OPTIONS'], csrf=False) + @http.route(prefix + 'user//switch_progres', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def switch_account_progres(self, **kw): id = int(kw.get('id')) -- cgit v1.2.3 From 463101a734c8b64cfca4b7cbff5d060295e841ef Mon Sep 17 00:00:00 2001 From: Miqdad Date: Mon, 18 Aug 2025 14:08:33 +0700 Subject: accept context from quotation website --- indoteknik_api/controllers/api_v1/sale_order.py | 68 ++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index d199cd84..374b49a2 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -544,13 +544,76 @@ class SaleOrder(controller.Controller): main_partner = partner_invoice.get_main_parent() _logger.info( f"Partner Info - Sales: {sales_partner.id}, Invoice: {partner_invoice.id}, Main: {main_partner.id}") - + + def _get_request_context(params, kw): + # 1) kw (querystring di route) + ctx = kw.get('context') + if ctx: + return str(ctx).strip().lower() + + # 2) querystring langsung + ctx = request.httprequest.args.get('context') + if ctx: + return str(ctx).strip().lower() + + # 3) form-encoded body + ctx = request.httprequest.form.get('context') + if ctx: + return str(ctx).strip().lower() + + # 4) JSON body (kalau ada) + try: + js = request.httprequest.get_json(force=False, silent=True) or {} + ctx = js.get('context') + if ctx: + return str(ctx).strip().lower() + except Exception: + pass + + # 5) fallback: dari hasil get_request_params kalau kamu tambahkan 'context' di mapping + try: + return str((params.get('value', {}) or {}).get('context') or '').strip().lower() + except Exception: + return '' + + ctx = _get_request_context(params, kw) + _logger.info(f"[checkout] context sources -> kw={repr(kw.get('context'))}, " + f"args={repr(request.httprequest.args.get('context'))}, " + f"form={repr(request.httprequest.form.get('context'))}, " + f"json={(request.httprequest.get_json(force=False, silent=True) or {}).get('context') if hasattr(request.httprequest,'get_json') else None}, " + f"normalized={ctx}") + + payment_term_id_value = 26 + + ctx = str((kw.get('context') or '')) + if ctx == 'quotation': + try: + creator_user_id = params['value'].get('user_id') or request.env.user.id + user = request.env['res.users'].sudo().browse(int(creator_user_id)) + + term_name = None + if user and user.exists() and user.partner_id: + prop = getattr(user.partner_id, 'property_payment_term_id', False) + # Kalau Many2one -> pakai .name, kalau string/selection -> cast ke str + if prop: + term_name = getattr(prop, 'name', False) or str(prop).strip() + + if term_name: + term = request.env['account.payment.term'].sudo().search( + [('name', 'ilike', term_name)], + limit=1 + ) + if term: + payment_term_id_value = term.id + except Exception as e: + _logger.warning(f"Gagal resolve payment term dari user: {e}") + parameters = { 'warehouse_id': 8, 'carrier_id': 1, 'sales_tax_id': 23, 'pricelist_id': user_pricelist or product_pricelist_default_discount_id, - 'payment_term_id': 26, + 'payment_term_id':payment_term_id_value, 'team_id': 2, 'company_id': 1, 'currency_id': 12, @@ -633,6 +696,7 @@ class SaleOrder(controller.Controller): _logger.info(f"Final is_has_disc: {is_has_disc}") + order_line = request.env['sale.order.line'].create({ 'company_id': 1, 'order_id': sale_order.id, -- cgit v1.2.3 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 @@ + + + +