diff options
| author | Azka Nathan <darizkyfaz@gmail.com> | 2024-10-04 14:23:59 +0700 |
|---|---|---|
| committer | Azka Nathan <darizkyfaz@gmail.com> | 2024-10-04 14:23:59 +0700 |
| commit | 48c220d1c38f435962b8b630c5209ba781ca30df (patch) | |
| tree | 628b39f7c40793b2029aa2267f9ea5af4f580ee0 | |
| parent | 7059f095dd09649f7c12f74ff29200f644bbc854 (diff) | |
push
| -rwxr-xr-x | indoteknik_custom/models/sale_order.py | 71 | ||||
| -rw-r--r-- | indoteknik_custom/models/sale_order_line.py | 8 | ||||
| -rw-r--r-- | indoteknik_custom/models/vendor_approval.py | 28 | ||||
| -rw-r--r-- | indoteknik_custom/models/website_user_cart.py | 2 | ||||
| -rw-r--r-- | indoteknik_custom/views/ir_sequence.xml | 10 | ||||
| -rwxr-xr-x | indoteknik_custom/views/sale_order.xml | 9 | ||||
| -rw-r--r-- | indoteknik_custom/views/vendor_approval.xml | 16 |
7 files changed, 110 insertions, 34 deletions
diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index a6ea6c81..0f22a7d4 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -135,6 +135,12 @@ class SaleOrder(models.Model): 'account.payment.term', string='Payment Terms', check_company=True, # Unrequired company domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True) + total_weight = fields.Float(string='Total Weight', compute='_compute_total_weight') + + def _compute_total_weight(self): + for order in self: + order.total_weight = sum(line.weight for line in order.order_line) + def action_estimate_shipping(self): total_weight = 0 missing_weight_products = [] @@ -155,38 +161,45 @@ class SaleOrder(models.Model): # Mendapatkan city_id berdasarkan nama kota origin_city_name = self.warehouse_id.partner_id.kota_id.name - destination_city_name = self.real_shipping_id.kota_id.name - origin_subdistrict_name = self.warehouse_id.partner_id.kecamatan_id.name - destination_subdistrict_name = self.real_shipping_id.kecamatan_id.name + destination_subsdistrict_id = self.real_shipping_id.kecamatan_id.rajaongkir_id - origin_id_city = self._get_city_id_by_name(origin_city_name) - destination_id_city = self._get_city_id_by_name(destination_city_name) - origin_city_id = self._get_subdistrict_id_by_name(origin_id_city, origin_subdistrict_name) - destination_city_id = self._get_subdistrict_id_by_name(destination_id_city, destination_subdistrict_name) - - if not origin_city_id or not destination_city_id: + if not destination_subsdistrict_id: raise UserError("Gagal mendapatkan ID kota asal atau tujuan.") - result = self._call_rajaongkir_api(total_weight, origin_city_id, destination_city_id) + result = self._call_rajaongkir_api(total_weight, destination_subsdistrict_id) if result: estimated_cost = result['rajaongkir']['results'][0]['costs'][0]['cost'][0]['value'] self.delivery_amt = estimated_cost - self.message_post(body=f"Estimasi Ongkos Kirim: {self.delivery_amt}") + shipping_info = [] + for courier in result['rajaongkir']['results']: + for cost_detail in courier['costs']: + service = cost_detail['service'] + description = cost_detail['description'] + etd = cost_detail['cost'][0]['etd'] + value = cost_detail['cost'][0]['value'] + shipping_info.append(f"Service: {service}, Description: {description}, ETD: {etd} hari, Cost: Rp {value}") + + log_message = "<br/>".join(shipping_info) + + description_ongkir = result['rajaongkir']['results'][0]['costs'][0]['description'] + etd_ongkir = result['rajaongkir']['results'][0]['costs'][0]['cost'][0]['etd'] + service_ongkir = result['rajaongkir']['results'][0]['costs'][0]['service'] + self.message_post(body=f"Estimasi Ongkos Kirim: Rp{self.delivery_amt}<br/>Service: {service_ongkir}<br/>Description: {description_ongkir}<br/>ETD: {etd_ongkir}<br/>Detail Lain:<br/>{log_message}") else: raise UserError("Gagal mendapatkan estimasi ongkir.") - def _call_rajaongkir_api(self, total_weight, origin_city_id, destination_city_id): + def _call_rajaongkir_api(self, total_weight, destination_subsdistrict_id): url = 'https://pro.rajaongkir.com/api/cost' headers = { - 'key': '7ac9883688da043b50cc32f0e3070bb6', + 'key': '9b1310f644056d84d60b0af6bb21611a', } courier = self.carrier_id.name.lower() data = { - 'origin': int(origin_city_id), + 'origin': 2127, 'originType': 'subdistrict', - 'destination': int(destination_city_id), + 'destination': int(destination_subsdistrict_id), 'destinationType': 'subdistrict', 'weight': int(total_weight * 1000), 'courier': courier, @@ -212,7 +225,7 @@ class SaleOrder(models.Model): def _get_city_id_by_name(self, city_name): url = 'https://pro.rajaongkir.com/api/city' headers = { - 'key': '7ac9883688da043b50cc32f0e3070bb6', + 'key': '9b1310f644056d84d60b0af6bb21611a', } normalized_city_name = self._normalize_city_name(city_name) @@ -228,14 +241,17 @@ class SaleOrder(models.Model): def _get_subdistrict_id_by_name(self, city_id, subdistrict_name): url = f'https://pro.rajaongkir.com/api/subdistrict?city={city_id}' headers = { - 'key': '7ac9883688da043b50cc32f0e3070bb6', + 'key': '9b1310f644056d84d60b0af6bb21611a', } response = requests.get(url, headers=headers) if response.status_code == 200: subdistrict_data = response.json() for subdistrict in subdistrict_data['rajaongkir']['results']: - if subdistrict['subdistrict_name'].lower() == subdistrict_name.lower(): + subsdistrict_1 = subdistrict['subdistrict_name'].lower() + subsdistrict_2 = subdistrict_name.lower() + + if subsdistrict_1 == subsdistrict_2: return subdistrict['subdistrict_id'] return None @@ -808,14 +824,24 @@ class SaleOrder(models.Model): def validate_different_vendor(self): different_vendor = self.order_line.filtered(lambda l: l.vendor_id and l.vendor_md_id and l.vendor_id.id != l.vendor_md_id.id) + + if self.vendor_approval_id and self.vendor_approval_id.state == 'draft': + raise UserError('SO ini sedang dalam review Vendor Approval') + + if self.vendor_approval_id and self.vendor_approval_id.state == 'cancel': + raise UserError('Vendor Approval SO ini Di Reject') + if different_vendor: vendor_approval = self.env['vendor.approval'].create({ 'order_id': self.id, + 'create_date_so': self.create_date, + 'partner_id': self.partner_id.id, 'state': 'draft', }) self.vendor_approval_id = vendor_approval.id - for line in self.line: + + for line in different_vendor: self.env['vendor.approval.line'].create({ 'vendor_approval_id': vendor_approval.id, 'product_id': line.product_id.id, @@ -824,11 +850,18 @@ class SaleOrder(models.Model): 'vendor_md_id': line.vendor_md_id.id, 'purchase_price': line.purchase_price, 'purchase_price_md': line.purchase_price_md, + 'sales_price': line.price_unit, + 'margin_before': line.margin_md, + 'margin_after': line.item_percent_margin, + 'purchase_tax_id': line.purchase_tax_id.id, + 'sales_tax_id': line.tax_id[0].id if line.tax_id else False, + 'percent_margin_difference': (line.price_unit - line.purchase_price_md) / line.purchase_price_md if line.purchase_price_md else False, }) return True else: return False + def action_confirm(self): for order in self: diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 06b0f53d..98a6c759 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -34,6 +34,7 @@ class SaleOrderLine(models.Model): reserved_from = fields.Char(string='Reserved From', copy=False) item_percent_margin_without_deduction = fields.Float('%Margin', compute='_compute_item_margin_without_deduction') weight = fields.Float(string='Weight') + margin_md = fields.Float(string='Margin MD') @api.constrains('note_procurement') def note_procurement_to_apo(self): @@ -127,6 +128,9 @@ class SaleOrderLine(models.Model): else: line.item_percent_margin = 0 + if not line.margin_md: + line.margin_md = line.item_percent_margin + @api.onchange('vendor_id') def onchange_vendor_id(self): # TODO : need to change this logic @stephan @@ -135,7 +139,6 @@ class SaleOrderLine(models.Model): elif self.product_id.categ_id.id == 34: # finish good / manufacturing only cost = self.product_id.standard_price self.purchase_price = cost - self.purchase_price_md = cost elif self.product_id.x_manufacture.override_vendor_id: # purchase_price = self.env['purchase.pricelist'].search( # [('vendor_id', '=', self.product_id.x_manufacture.override_vendor_id.id), @@ -143,8 +146,6 @@ class SaleOrderLine(models.Model): # limit=1, order='count_trx_po desc, count_trx_po_vendor desc') price, taxes, vendor_id = self._get_purchase_price_by_vendor(self.product_id, self.vendor_id) self.purchase_price = price - self.purchase_price_md = price - self.vendor_md_id = self.vendor_id self.purchase_tax_id = taxes # else: # purchase_price = self.env['purchase.pricelist'].search( @@ -251,6 +252,7 @@ class SaleOrderLine(models.Model): price, taxes, vendor_id = self._get_purchase_price(line.product_id) line.vendor_id = vendor_id line.vendor_md_id = vendor_id + line.margin_md = line.item_percent_margin line.tax_id = line.order_id.sales_tax_id # price, taxes = line._get_valid_purchase_price(purchase_price) line.purchase_price = price diff --git a/indoteknik_custom/models/vendor_approval.py b/indoteknik_custom/models/vendor_approval.py index 442aec7a..e540b8fc 100644 --- a/indoteknik_custom/models/vendor_approval.py +++ b/indoteknik_custom/models/vendor_approval.py @@ -15,21 +15,35 @@ class VendorApproval(models.Model): partner_id = fields.Many2one('res.partner', string="Customer", readonly=True) order_id = fields.Many2one('sale.order', string="SO", readonly=True) vendor_approval_line = fields.One2many('vendor.approval.line', 'vendor_approval_id', string='Vendor Approval Lines', auto_join=True) - state = fields.Selection([('draft', 'Draft'), ('done', 'Done'), ('cancel', 'Cancel')], string='State', tracking=True) + state = fields.Selection([('draft', 'Draft'), ('done', 'Done'), ('cancel', 'Reject')], string='State', tracking=True) + create_date_so = fields.Datetime(string='Create Date SO', readonly=True) + + @api.model + def create(self, vals): + vals['number'] = self.env['ir.sequence'].next_by_code('vendor.approval') or '0' + result = super(VendorApproval, self).create(vals) + return result def action_approve(self): if not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'): raise UserError('Hanya Merchandiser yang bisa approve') + self.state = 'done' self.order_id.update({'vendor_approval': True}) self.order_id.action_confirm() + message = "Vendor Approval approved by %s" % (self.env.user.name) + self.order_id.message_post(body=message) + - def action_reject(self): if not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'): raise UserError('Hanya Merchandiser yang bisa cancel') + self.state = 'cancel' + message = "Vendor Approval rejected by %s" % (self.env.user.name) + self.order_id.message_post(body=message) + def unlink(self): res = super(VendorApproval, self).unlink() if not self._name == 'vendor.approval': @@ -47,7 +61,13 @@ class VendorApprovalLine(models.Model): product_uom_qty = fields.Float(string='Quantity') vendor_id = fields.Many2one('res.partner', string='Vendor') vendor_md_id = fields.Many2one('res.partner', string='Vendor MD') - purchase_price = fields.Many2one(string='Purchase Price') - purchase_price_md= fields.Many2one(string='Purchase Price MD') + sales_price = fields.Float(string='Sales Price') + margin_before = fields.Float(string='Margin Before') + margin_after = fields.Float(string='Margin After') + purchase_price = fields.Float(string='Purchase Price') + purchase_price_md= fields.Float(string='Purchase Price MD') + purchase_tax_id = fields.Many2one('account.tax', string='Purchase Tax', domain=['|', ('active', '=', False), ('active', '=', True)]) + sales_tax_id = fields.Many2one('account.tax', string='Sales Tax', domain=['|', ('active', '=', False), ('active', '=', True)]) + percent_margin_difference = fields.Float(string='Percent Margin Difference') diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index 169f4a6b..8a321187 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -173,7 +173,7 @@ class WebsiteUserCart(models.Model): } return result - def action_mail_reminder_to_checkout(self, limit=10): + def action_mail_reminder_to_checkout(self, limit=250): user_ids = self.search([]).mapped('user_id')[:limit] for user in user_ids: diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml index dd501d8c..dfb56100 100644 --- a/indoteknik_custom/views/ir_sequence.xml +++ b/indoteknik_custom/views/ir_sequence.xml @@ -21,6 +21,16 @@ <field name="number_increment">1</field> </record> + <record id="sequence_vendor_approval" model="ir.sequence"> + <field name="name">Vendor Approval</field> + <field name="code">vendor.approval</field> + <field name="active">TRUE</field> + <field name="prefix">VA/%(year)s/</field> + <field name="padding">5</field> + <field name="number_next">1</field> + <field name="number_increment">1</field> + </record> + <record id="sequence_approval_unreserve" model="ir.sequence"> <field name="name">Approval Unreserve</field> <field name="code">approval.unreserve</field> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index f2a57fc7..9a637441 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -72,6 +72,7 @@ <field name="flash_sale"/> <field name="margin_after_delivery_purchase"/> <field name="percent_margin_after_delivery_purchase"/> + <field name="total_weight"/> </field> <field name="analytic_account_id" position="after"> <field name="customer_type" required="1"/> @@ -80,6 +81,7 @@ <field name="email" required="1"/> <field name="unreserve_id"/> <field name="due_id" readonly="1"/> + <field name="vendor_approval_id" readonly="1"/> <field name="source_id" domain="[('id', 'in', [32, 59, 60, 61])]" required="1"/> <button name="override_allow_create_invoice" string="Override Create Invoice" @@ -117,7 +119,7 @@ </xpath> <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='price_total']" position="after"> <field name="vendor_id" attrs="{'readonly': [('parent.approval_status', '=', 'approved')]}" domain="[('parent_id', '=', False)]" options="{'no_create':True}"/> - <field name="vendor_md_id" readonly="1" options="{'no_create':True}"/> + <field name="vendor_md_id" optional="hide"/> <field name="purchase_price" attrs=" { 'readonly': [ @@ -127,14 +129,15 @@ ] } "/> - <field name="purchase_price_md" readonly="1"/> + <field name="purchase_price_md" optional="hide"/> <field name="purchase_tax_id" attrs="{'readonly': [('parent.approval_status', '!=', False)]}" domain="[('type_tax_use','=','purchase')]" options="{'no_create':True}"/> <field name="item_percent_margin"/> <field name="item_margin" optional="hide"/> + <field name="margin_md" optional="hide"/> <field name="note" optional="hide"/> <field name="note_procurement" optional="hide"/> <field name="vendor_subtotal" optional="hide"/> - <field name="weight" optional="hide"/> + <field name="weight" optional="hide"/> <field name="amount_voucher_disc" string="Voucher" readonly="1" optional="hide"/> <field name="order_promotion_id" string="Promotion" readonly="1" optional="hide"/> </xpath> diff --git a/indoteknik_custom/views/vendor_approval.xml b/indoteknik_custom/views/vendor_approval.xml index c3f5ee77..605edfbf 100644 --- a/indoteknik_custom/views/vendor_approval.xml +++ b/indoteknik_custom/views/vendor_approval.xml @@ -7,8 +7,9 @@ <field name="arch" type="xml"> <tree default_order="create_date desc" create="0"> <field name="number"/> - <field name="partner_id"/> + <field name="create_date_so"/> <field name="order_id"/> + <field name="partner_id"/> <field name="state"/> </tree> </field> @@ -20,11 +21,17 @@ <field name="arch" type="xml"> <tree> <field name="product_id"/> + <field name="sales_price"/> <field name="product_uom_qty"/> + <field name="sales_tax_id"/> + <field name="margin_after"/> <field name="vendor_id"/> <field name="vendor_md_id"/> <field name="purchase_price"/> <field name="purchase_price_md"/> + <field name="margin_before"/> + <field name="purchase_tax_id"/> + <field name="percent_margin_difference"/> </tree> </field> </record> @@ -38,12 +45,12 @@ <button name="action_approve" string="Approve" type="object" - attrs="{'invisible': [('state', '=', 'done')]}" + attrs="{'invisible': [('state', 'not in', ['draft'])]}" /> <button name="action_reject" - string="Cancel" + string="Reject" type="object" - attrs="{'invisible': [('state', '=', 'cancel')]}" + attrs="{'invisible': [('state', 'not in', ['draft'])]}" /> </header> <sheet> @@ -52,6 +59,7 @@ <field name="partner_id" readonly="1"/> <field name="order_id" readonly="1"/> <field name="state" readonly="1"/> + <field name="create_date_so" readonly="1"/> </group> </group> <notebook> |
