summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIT Fixcomart <it@fixcomart.co.id>2024-03-12 04:56:55 +0000
committerIT Fixcomart <it@fixcomart.co.id>2024-03-12 04:56:55 +0000
commitf43c76e2e7fb1a2e46f6e698afb1da74961cad50 (patch)
tree18b80d3d6dd74022f01d0663d4a349be6c662193
parent41056a3fcf9cf80ac3609ab32223ffbac5b3ad83 (diff)
parentb7b71be97a73f454f2df9fd9a37f5017c82192ae (diff)
Merged in feature/web-sale-approval (pull request #136)
Feature/web sale approval
-rw-r--r--indoteknik_api/controllers/api_v1/sale_order.py74
-rw-r--r--indoteknik_api/models/__init__.py1
-rw-r--r--indoteknik_api/models/res_partner.py14
-rw-r--r--indoteknik_api/models/res_users.py29
-rw-r--r--indoteknik_api/models/sale_order.py7
-rw-r--r--indoteknik_custom/models/res_partner.py15
-rwxr-xr-xindoteknik_custom/models/sale_order.py33
-rw-r--r--indoteknik_custom/views/res_partner.xml4
-rwxr-xr-xindoteknik_custom/views/sale_order.xml45
9 files changed, 205 insertions, 17 deletions
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/<id>', 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/<id>/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/<id>/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/<id>/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..456e52d7 100644
--- a/indoteknik_api/models/res_users.py
+++ b/indoteknik_api/models/res_users.py
@@ -6,27 +6,32 @@ 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
+ main_partner = partner.get_main_parent()
+
+ WEB_ROLE_ALIAS = {
+ 'manager': 2,
+ 'director': 3
+ }
data = {
'id': res_user.id,
- 'parent_id': res_user.parent_id.id or False,
- 'parent_name': res_user.parent_id.name or False,
- 'partner_id': res_user.partner_id.id,
+ 'parent_id': res_user.parent_id.id or None,
+ 'parent_name': res_user.parent_id.name or None,
+ 'partner_id': partner.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': main_partner.company_type == 'company',
+ 'pricelist': res_user.property_product_pricelist.sudo().get_tier_name(),
+ 'web_role': WEB_ROLE_ALIAS[partner.web_role] if partner.web_role else None,
+ 'feature': {
+ 'so_approval': main_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_api/models/sale_order.py b/indoteknik_api/models/sale_order.py
index 85bf5015..1c0180ec 100644
--- a/indoteknik_api/models/sale_order.py
+++ b/indoteknik_api/models/sale_order.py
@@ -5,6 +5,12 @@ class SaleOrder(models.Model):
_inherit = 'sale.order'
def api_v1_single_response(self, sale_order, context=False):
+ APPROVAL_STEP = {
+ 'company': 1,
+ 'cust_manager': 2,
+ 'cust_director': 3,
+ }
+
data = {
'token': self.env['rest.api'].md5_salt(sale_order.id, 'sale.order'),
'id': sale_order.id,
@@ -17,6 +23,7 @@ class SaleOrder(models.Model):
'purchase_order_file': True if sale_order.partner_purchase_order_file else False,
'invoice_count': sale_order.invoice_count,
'status': 'draft',
+ 'approval_step': APPROVAL_STEP[sale_order.web_approval] if sale_order.web_approval else 0,
'date_order': self.env['rest.api'].datetime_to_str(sale_order.date_order, '%d/%m/%Y %H:%M:%S'),
'pickings': []
}
diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py
index a7302245..467d3be9 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)
@@ -31,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 759329b0..b7578da0 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
@@ -445,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')
@@ -472,6 +484,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")
@@ -631,7 +646,23 @@ class SaleOrder(models.Model):
line.discount = line.initial_discount
line.initial_discount = False
-
+ def action_web_approve(self):
+ if self.env.uid != self.partner_id.user_id.id:
+ 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',
+ 'params': {
+ 'title': 'Notification',
+ 'message': 'Berhasil approve web order',
+ 'next': {'type': 'ir.actions.act_window_close'},
+ }
+ }
diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml
index da2dec99..370fcf7b 100644
--- a/indoteknik_custom/views/res_partner.xml
+++ b/indoteknik_custom/views/res_partner.xml
@@ -26,6 +26,10 @@
<group name="purchase" position="inside">
<field name="leadtime"/>
</group>
+ <field name="vat" position="after">
+ <field name="use_so_approval" attrs="{'invisible': [('parent_id', '!=', False), ('company_type', '!=', 'company')]}" />
+ <field name="web_role" attrs="{'invisible': ['|', ('parent_id', '=', False), ('company_type', '=', 'company')]}" />
+ </field>
</field>
</record>
</data>
diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml
index 64e6ad7b..97726ed7 100755
--- a/indoteknik_custom/views/sale_order.xml
+++ b/indoteknik_custom/views/sale_order.xml
@@ -16,10 +16,16 @@
type="object"
attrs="{'invisible': [('approval_status', 'in', ['pengajuan1', 'pengajuan2', 'approved'])]}"
/>
+ <button name="action_web_approve"
+ string="Web Approve"
+ type="object"
+ attrs="{'invisible': ['|', '|', ('create_uid', '!=', 25), ('web_approval', '!=', False), ('state', '!=', 'draft')]}"
+ />
<button name="indoteknik_custom.action_view_uangmuka_penjualan" string="UangMuka"
type="action" attrs="{'invisible': [('approval_status', '!=', 'approved')]}"/>
</button>
<field name="payment_term_id" position="after">
+ <field name="create_uid" invisible="1"/>
<field name="create_date" invisible="1"/>
<field name="shipping_cost_covered" attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-15'), ('create_date', '=', False)]}"/>
<field name="shipping_paid_by" attrs="{'required': ['|', ('create_date', '&gt;', '2023-06-15'), ('create_date', '=', False)]}"/>
@@ -142,6 +148,7 @@
<field name="partner_purchase_order_name" readonly="True"/>
<field name="partner_purchase_order_description" readonly="True"/>
<field name="partner_purchase_order_file" readonly="True"/>
+ <field name="web_approval" readonly="True"/>
</group>
<group>
<button name="generate_payment_link_midtrans_sales_order"
@@ -222,5 +229,43 @@
<field name="state">code</field>
<field name="code">action = records.open_form_multi_update_status()</field>
</record>
+
+ <record id="mail_template_sale_order_web_approve_notification" model="mail.template">
+ <field name="name">Sale Order: Web Approve Notification</field>
+ <field name="model_id" ref="indoteknik_custom.model_sale_order"/>
+ <field name="subject">Permintaan Persetujuan Pesanan ${object.name} di Indoteknik.com</field>
+ <field name="email_from">sales@indoteknik.com</field>
+ <field name="email_to">${object.partner_id.email | safe}</field>
+ <field name="email_cc">${object.partner_id.get_approve_partner_ids("email_comma_sep")}</field>
+ <field name="body_html" type="html">
+ <table border="0" cellpadding="0" cellspacing="0" style="padding: 16px 0; background-color: #F1F1F1; font-family:Inter, Helvetica, Verdana, Arial,sans-serif; line-height: 24px; color: #454748; width: 100%; border-collapse:separate;">
+ <tr><td align="center">
+ <table border="0" cellpadding="0" cellspacing="0" width="590" style="font-size: 13px; padding: 16px; background-color: white; color: #454748; border-collapse:separate;">
+ <tbody>
+ <tr>
+ <td align="center" style="min-width: 590px;">
+ <table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
+ <tr><td style="padding-bottom: 24px;">Dear ${(object.partner_id.get_main_parent()).name},</td></tr>
+
+ <tr><td style="padding-bottom: 16px;">Ini adalah konfirmasi pesanan dari ${object.partner_id.name | safe} untuk nomor pesanan ${object.name} yang memerlukan persetujuan agar dapat diproses.</td></tr>
+ <tr><td style="padding-bottom: 16px;">
+ <a href="https://indoteknik.com/my/quotations/${object.id}" style="color: white; background-color: #C53030; border: none; border-radius: 6px; padding: 4px 8px; width: fit-content; display: block;">
+ Lihat Pesanan
+ </a>
+ </td></tr>
+ <tr><td style="padding-bottom: 16px;">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.</td></tr>
+
+ <tr><td style="padding-bottom: 2px;">Hormat kami,</td></tr>
+ <tr><td style="padding-bottom: 2px;">PT. Indoteknik Dotcom Gemilang</td></tr>
+ <tr><td style="padding-bottom: 2px;">sales@indoteknik.com</td></tr>
+ </table>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </td></tr>
+ </table>
+ </field>
+ </record>
</data>
</odoo> \ No newline at end of file