From f53312f3f2c78d50d838c249a8d0eb1ed1e5b7f2 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 5 Mar 2024 16:05:41 +0700 Subject: Add web sale approval feature --- indoteknik_api/controllers/api_v1/sale_order.py | 74 +++++++++++++++++++++++-- indoteknik_api/models/__init__.py | 1 + indoteknik_api/models/res_partner.py | 14 +++++ indoteknik_api/models/res_users.py | 21 ++++--- indoteknik_custom/models/res_partner.py | 6 ++ indoteknik_custom/models/sale_order.py | 5 ++ indoteknik_custom/views/res_partner.xml | 4 ++ indoteknik_custom/views/sale_order.xml | 1 + 8 files changed, 111 insertions(+), 15 deletions(-) create mode 100644 indoteknik_api/models/res_partner.py diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 62f20ed8..53a9b127 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -79,12 +79,14 @@ class SaleOrder(controller.Controller): ('name', 'ilike', '%' + name + '%'), ('partner_purchase_order_name', 'ilike', '%' + name + '%') ] + sale_orders = request.env['sale.order'].search( domain, offset=offset, limit=limit) data = { 'sale_order_total': request.env['sale.order'].search_count(domain), 'sale_orders': [request.env['sale.order'].api_v1_single_response(x) for x in sale_orders] } + return self.response(data) @http.route(PREFIX_PARTNER + 'sale_order/', auth='public', method=['GET', 'OPTIONS']) @@ -102,8 +104,7 @@ class SaleOrder(controller.Controller): data = {} sale_order = request.env['sale.order'].search(domain) if sale_order: - data = request.env['sale.order'].api_v1_single_response( - sale_order, context='with_detail') + data = request.env['sale.order'].api_v1_single_response(sale_order, context='with_detail') return self.response(data) @@ -117,8 +118,7 @@ class SaleOrder(controller.Controller): if not params['valid']: return self.response(code=400, description=params) - partner_child_ids = self.get_partner_child_ids( - params['value']['partner_id']) + partner_child_ids = self.get_partner_child_ids(params['value']['partner_id']) domain = [ ('id', '=', params['value']['id']), ('partner_id', 'in', partner_child_ids) @@ -131,6 +131,72 @@ class SaleOrder(controller.Controller): sale_order, context='with_detail') return self.response(data) + + @http.route(PREFIX_PARTNER + 'sale_order//approve', auth='public', method=['POST', 'OPTIONS'], csrf=False) + @controller.Controller.must_authorized(private=True, private_key='partner_id') + def partner_approve_sale_order_by_id(self, **kw): + params = self.get_request_params(kw, { + 'partner_id': ['number'], + 'id': ['number'] + }) + + if not params['valid']: + return self.response(code=400, description=params) + + value = params['value'] + partner_child_ids = self.get_partner_child_ids(value['partner_id']) + + sale_order = request.env['sale.order'].search([ + ('id', '=', value['id']), + ('partner_id', 'in', partner_child_ids) + ]) + if not sale_order: + return self.response(code=404, description='Sale Order not found') + + partner = request.env['res.partner'].browse(value['partner_id']) + if not partner.web_role: + return self.response(code=400, description='Unauthorized') + + if partner.web_role: + sale_order.web_approval = 'cust_%s' % partner.web_role + + if sale_order.web_approval == 'cust_director': + sale_order.approval_status = 'pengajuan1' + + return self.response('success') + + @http.route(PREFIX_PARTNER + 'sale_order//reject', auth='public', method=['POST', 'OPTIONS'], csrf=False) + @controller.Controller.must_authorized(private=True, private_key='partner_id') + def partner_reject_sale_order_by_id(self, **kw): + params = self.get_request_params(kw, { + 'partner_id': ['number'], + 'id': ['number'] + }) + + if not params['valid']: + return self.response(code=400, description=params) + + value = params['value'] + partner_child_ids = self.get_partner_child_ids(value['partner_id']) + + sale_order = request.env['sale.order'].search([ + ('id', '=', value['id']), + ('partner_id', 'in', partner_child_ids) + ]) + if not sale_order: + return self.response(code=404, description='Sale Order not found') + + partner = request.env['res.partner'].browse(value['partner_id']) + if not partner.web_role: + return self.response(code=400, description='Unauthorized') + + if partner.web_role: + sale_order.web_approval = 'cust_%s' % partner.web_role + + sale_order.state = 'cancel' + sale_order.approval_status = False + + return self.response('success') @http.route(PREFIX_PARTNER + 'sale_order//upload_po', auth='public', method=['POST', 'OPTIONS'], csrf=False) def partner_upload_po_sale_order(self, **kw): diff --git a/indoteknik_api/models/__init__.py b/indoteknik_api/models/__init__.py index 892d2657..8c85938c 100644 --- a/indoteknik_api/models/__init__.py +++ b/indoteknik_api/models/__init__.py @@ -9,3 +9,4 @@ from . import sale_order from . import x_manufactures from . import website_content from . import coupon_program +from . import res_partner diff --git a/indoteknik_api/models/res_partner.py b/indoteknik_api/models/res_partner.py new file mode 100644 index 00000000..57200ac1 --- /dev/null +++ b/indoteknik_api/models/res_partner.py @@ -0,0 +1,14 @@ +from odoo import models + + +class ResPartner(models.Model): + _inherit = 'res.partner' + + def get_main_parent(self): + partner = self + + while partner.parent_id: + partner = partner.parent_id + + return partner + \ No newline at end of file diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py index f331321f..eecab6ef 100644 --- a/indoteknik_api/models/res_users.py +++ b/indoteknik_api/models/res_users.py @@ -6,27 +6,26 @@ class ResUsers(models.Model): def api_single_response(self, res_user, with_detail=''): config = self.env['ir.config_parameter'] - - user_pricelist = res_user.property_product_pricelist - pricelist_tier = user_pricelist.sudo().get_tier_name() + + partner = res_user.partner_id.get_main_parent() data = { 'id': res_user.id, - 'parent_id': res_user.parent_id.id or False, - 'parent_name': res_user.parent_id.name or False, + 'parent_id': res_user.parent_id.id or None, + 'parent_name': res_user.parent_id.name or None, 'partner_id': res_user.partner_id.id, 'name': res_user.name, 'email': res_user.login, 'phone': res_user.phone or '', 'mobile': res_user.mobile or '', 'external': res_user.share, - 'company': res_user.company_type == 'company', - 'pricelist': pricelist_tier + 'company': partner.company_type == 'company', + 'pricelist': res_user.property_product_pricelist.sudo().get_tier_name(), + 'web_role': partner.web_role or None, + 'feature': { + 'so_approval': partner.use_so_approval + } } - - - if res_user.parent_id: - data.update({ 'company': res_user.parent_id.company_type == 'company' }) return data diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index a7302245..c7b8865f 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -23,6 +23,12 @@ class ResPartner(models.Model): digital_invoice_tax = fields.Boolean(string="Digital Invoice & Faktur Pajak") is_potential = fields.Boolean(string='Potential') pakta_integritas = fields.Boolean(string='Pakta Integritas') + + use_so_approval = fields.Boolean(string='Use SO Approval') + web_role = fields.Selection([ + ('manager', 'Manager'), + ('director', 'Director') + ], string='Web Role') def get_child_ids(self): partner = self.env['res.partner'].search([('id', '=', self.id)], limit=1) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index f44f624e..988f13c8 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -88,6 +88,11 @@ class SaleOrder(models.Model): picking_iu_id = fields.Many2one('stock.picking', 'Picking IU') helper_by_id = fields.Many2one('res.users', 'Helper By') eta_date = fields.Datetime(string='ETA Date', copy=False, compute='_compute_eta_date') + web_approval = fields.Selection([ + ('company', 'Company'), + ('cust_manager', 'Customer Manager'), + ('cust_director', 'Customer Director') + ], string='Web Approval', copy=False) def _compute_eta_date(self): max_leadtime = 0 diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index da2dec99..c050ec62 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -26,6 +26,10 @@ + + + + diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 64e6ad7b..8e05c2e7 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -142,6 +142,7 @@ + + -- cgit v1.2.3 From 46d50e970b14ca7f3a8da53702ef2933178dbbf0 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 6 Mar 2024 13:49:43 +0700 Subject: Fix cancel web approval in sale order --- indoteknik_custom/models/sale_order.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index d4c70fdc..fb6a457d 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -477,6 +477,9 @@ class SaleOrder(models.Model): raise UserError("Invoice harus di Cancel dahulu") elif self.have_outstanding_picking: raise UserError("DO harus di Cancel dahulu") + + if not self.web_approval: + self.web_approval = 'company' # elif self.have_outstanding_po: # raise UserError("PO harus di Cancel dahulu") -- cgit v1.2.3 From 29dfec334ebf6a15a8a66e4af564fd5d812d8d67 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 6 Mar 2024 15:42:12 +0700 Subject: Add validation confirm when partner use approval feature --- indoteknik_custom/models/sale_order.py | 7 +++++++ indoteknik_custom/views/res_partner.xml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index fb6a457d..0cd7067a 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -450,6 +450,13 @@ class SaleOrder(models.Model): order._validate_order() order.order_line.validate_line() + main_parent = order.partner_id.get_main_parent() + SYSTEM_UID = 25 + FROM_WEBSITE = order.create_uid.id == SYSTEM_UID + + if FROM_WEBSITE and main_parent.use_so_approval and order.web_approval != 'cust_director': + raise UserError("This order not yet approved by customer director") + if order.validate_partner_invoice_due(): return self._create_notification_action('Notification', 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension') diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index c050ec62..370fcf7b 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -28,7 +28,7 @@ - + -- cgit v1.2.3 From b7b71be97a73f454f2df9fd9a37f5017c82192ae Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 12 Mar 2024 11:50:21 +0700 Subject: Add email template notification web approve on sale order --- indoteknik_custom/models/res_partner.py | 9 ++++++++ indoteknik_custom/models/sale_order.py | 3 +++ indoteknik_custom/views/sale_order.xml | 38 +++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index c7b8865f..467d3be9 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -37,6 +37,15 @@ class ResPartner(models.Model): partner_child_ids += [x['id'] for x in partner.parent_id.child_ids] partner_child_ids += [partner.parent_id.id] return partner_child_ids + + def get_approve_partner_ids(self, type=False): + parent = self.parent_id or self + partners = self.search([('parent_id', '=', parent.id), ('web_role', 'in', ['manager', 'director'])]) + + if type == 'email_comma_sep': + return ",".join([x.email for x in partners]) + + return partners @api.constrains('kota_id') def update_product_solr_flag(self): diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 0cd7067a..b7578da0 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -651,6 +651,9 @@ class SaleOrder(models.Model): raise UserError('You are not authorized to approve this order. Only %s can approve this order.' % self.partner_id.user_id.name) self.web_approval = 'company' + template = self.env.ref('indoteknik_custom.mail_template_sale_order_web_approve_notification') + template.send_mail(self.id, force_send=True) + return { 'type': 'ir.actions.client', 'tag': 'display_notification', diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 8e0c9bbe..97726ed7 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -229,5 +229,43 @@ code action = records.open_form_multi_update_status() + + + Sale Order: Web Approve Notification + + Permintaan Persetujuan Pesanan ${object.name} di Indoteknik.com + sales@indoteknik.com + ${object.partner_id.email | safe} + ${object.partner_id.get_approve_partner_ids("email_comma_sep")} + + + +
+ + + + + + +
+ + + + + + + + + + +
Dear ${(object.partner_id.get_main_parent()).name},
Ini adalah konfirmasi pesanan dari ${object.partner_id.name | safe} untuk nomor pesanan ${object.name} yang memerlukan persetujuan agar dapat diproses.
+ + Lihat Pesanan + +
Mohon segera melakukan tinjauan terhadap pesanan ini dan memberikan persetujuan. Terima kasih atas perhatian dan kerjasama Anda. Kami berharap dapat segera melanjutkan proses pesanan ini setelah mendapatkan persetujuan Anda.
Hormat kami,
PT. Indoteknik Dotcom Gemilang
sales@indoteknik.com
+
+
+
+
\ No newline at end of file -- cgit v1.2.3