diff options
| author | it-fixcomart <it@fixcomart.co.id> | 2024-10-08 15:24:18 +0700 |
|---|---|---|
| committer | it-fixcomart <it@fixcomart.co.id> | 2024-10-08 15:24:18 +0700 |
| commit | 2fcddbb073a04ed6ba0e9666a8ab5082a3ef4073 (patch) | |
| tree | d4a3a423adf53ea8c086397abbcfe05a369fe637 | |
| parent | ec1e2331be248a505d89c00244d6b0fe5bd61c26 (diff) | |
| parent | ce1c714c95f68b07f9b891600ba1e3b88288652c (diff) | |
Merge branch 'production' into iman/telegram
# Conflicts:
# indoteknik_custom/models/__init__.py
20 files changed, 413 insertions, 39 deletions
diff --git a/indoteknik_api/controllers/api_v1/__init__.py b/indoteknik_api/controllers/api_v1/__init__.py index 2d774071..6f27eec5 100644 --- a/indoteknik_api/controllers/api_v1/__init__.py +++ b/indoteknik_api/controllers/api_v1/__init__.py @@ -28,4 +28,5 @@ from . import midtrans from . import wati from . import courier from . import voucher -from . import stock_picking
\ No newline at end of file +from . import stock_picking +from . import state
\ No newline at end of file diff --git a/indoteknik_api/controllers/api_v1/city.py b/indoteknik_api/controllers/api_v1/city.py index 6e0e3edb..afe92c4a 100644 --- a/indoteknik_api/controllers/api_v1/city.py +++ b/indoteknik_api/controllers/api_v1/city.py @@ -15,10 +15,16 @@ class City(controller.Controller): name = '%' + name.replace(' ', '%') + '%' parameters.append(('name', 'ilike', name)) - cities = request.env['vit.kota'].search(parameters) + state_id = kw.get('state_id') + if state_id: + parameters.append(('state_id', '=', int(state_id))) + + districts = request.env['vit.kota'].search(parameters) data = [] - for city in cities: - data.append({ 'id': city.id, 'name': city.name }) + for district in districts: + data.append({ 'id': district.id, 'name': district.name }) return self.response(data) + + diff --git a/indoteknik_api/controllers/api_v1/partner.py b/indoteknik_api/controllers/api_v1/partner.py index 833b3302..a7925a02 100644 --- a/indoteknik_api/controllers/api_v1/partner.py +++ b/indoteknik_api/controllers/api_v1/partner.py @@ -69,6 +69,7 @@ class Partner(controller.Controller): 'mobile': ['required'], 'phone': [''], 'street': ['required'], + 'state_id': ['required', 'number', 'alias:state_id'], 'city_id': ['required', 'number', 'alias:kota_id'], 'district_id': ['number', 'alias:kecamatan_id'], 'sub_district_id': ['number', 'alias:kelurahan_id', 'exclude_if_null'], @@ -82,7 +83,7 @@ class Partner(controller.Controller): partner = request.env[self._name].search([('id', '=', params['value']['id'])], limit=1) if not partner: return self.response(code=404, description='User not found') - + partner.write(params['value']) return self.response({ @@ -100,10 +101,11 @@ class Partner(controller.Controller): 'mobile': ['required'], 'phone': [''], 'street': ['required'], + 'state_id': ['required', 'number', 'alias:state_id'], 'city_id': ['required', 'number', 'alias:kota_id'], 'district_id': ['number', 'alias:kecamatan_id'], 'sub_district_id': ['number', 'alias:kelurahan_id', 'exclude_if_null'], - 'zip': ['required'], + 'zip': ['required'] }) if not params['valid']: diff --git a/indoteknik_api/controllers/api_v1/state.py b/indoteknik_api/controllers/api_v1/state.py new file mode 100644 index 00000000..598ef70b --- /dev/null +++ b/indoteknik_api/controllers/api_v1/state.py @@ -0,0 +1,24 @@ +from .. import controller +from odoo import http +from odoo.http import request + +class District(controller.Controller): + prefix = '/api/v1/' + + @http.route(prefix + 'state', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_state(self, **kw): + parameters = [] + + name = kw.get('name') + if name: + name = '%' + name.replace(' ', '%') + '%' + parameters.append(('name', 'ilike', name)) + + states = request.env['res.country.state'].search(parameters) + data = [] + for state in states: + data.append({ 'id': state.id, 'name': state.name }) + + return self.response(data) + diff --git a/indoteknik_api/controllers/api_v1/user.py b/indoteknik_api/controllers/api_v1/user.py index 52d773e2..c7bfe91a 100644 --- a/indoteknik_api/controllers/api_v1/user.py +++ b/indoteknik_api/controllers/api_v1/user.py @@ -94,7 +94,13 @@ class User(controller.Controller): user = request.env['res.users'].create(user_data) user.partner_id.email = email - + user.partner_id.customer_type = 'nonpkp' + user.partner_id.npwp = '0.000.000.0-000.000' + user.partner_id.sppkp = '-' + user.partner_id.nama_wajib_pajak = user.name + user.partner_id.user_id = 3222 + user.partner_id.property_account_receivable_id = 395 + user.partner_id.property_account_payable_id = 438 data = { 'is_auth': True, 'user': self.response_with_token(user) @@ -149,6 +155,7 @@ class User(controller.Controller): 'name': name, 'login': email, 'mobile': phone, + 'phone': phone, 'password': password, 'active': False, 'sel_groups_1_9_10': 9 diff --git a/indoteknik_api/models/res_users.py b/indoteknik_api/models/res_users.py index b2e8acfe..534898e1 100644 --- a/indoteknik_api/models/res_users.py +++ b/indoteknik_api/models/res_users.py @@ -48,6 +48,7 @@ class ResUsers(models.Model): 'street': user.street or '', 'street2': user.street2 or '', 'city': None, + 'state_id': None, 'district': None, 'sub_district': None, 'zip': user.zip or '', @@ -60,12 +61,18 @@ class ResUsers(models.Model): 'alamat_bisnis': user.street or None, } + if user.state_id: + data['state_id'] = { + 'id': user.state_id.id, + 'name': user.state_id.name + } or None + if user.kota_id: data['city'] = { 'id': user.kota_id.id, 'name': user.kota_id.name } or None - + if user.kecamatan_id: data['district'] = { 'id': user.kecamatan_id.id, diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 3104b9a3..234ccebb 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -144,6 +144,7 @@ 'views/partner_payment_term.xml', 'views/vendor_payment_term.xml', 'views/approval_unreserve.xml', + 'views/vendor_approval.xml', 'report/report.xml', 'report/report_banner_banner.xml', 'report/report_banner_banner2.xml', diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 1620c82e..13c48673 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -128,4 +128,6 @@ from . import sales_order_reject from . import approval_date_doc from . import account_tax from . import approval_unreserve +from . import vendor_approval +from . import partner from . import website_telegram diff --git a/indoteknik_custom/models/partner.py b/indoteknik_custom/models/partner.py new file mode 100644 index 00000000..46dc751a --- /dev/null +++ b/indoteknik_custom/models/partner.py @@ -0,0 +1,7 @@ +from odoo import fields, models, api, _ +from odoo.exceptions import AccessError, UserError, ValidationError + +class kota(models.Model): + _inherit = 'vit.kota' + + is_jabodetabek = fields.Boolean(string='Jabodetabek', default=False)
\ No newline at end of file diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 8a47482a..08408506 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -503,6 +503,9 @@ class PurchaseOrder(models.Model): current_time = datetime.now() self.check_ppn_mix() # self.check_data_vendor() + + if self.amount_untaxed >= 50000000 and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'): + raise UserError("Hanya Merchandiser yang bisa approve") if self.total_percent_margin < self.total_so_percent_margin and not self.env.user.is_purchasing_manager and not self.env.user.is_leader: raise UserError("Beda Margin dengan Sales, harus approval Manager") @@ -634,6 +637,8 @@ class PurchaseOrder(models.Model): template.send_mail(self.id, force_send=True) def po_approve(self): + if self.amount_untaxed >= 50000000 and not self.env.user.has_group('indoteknik_custom.group_role_merchandiser'): + raise UserError("Hanya Merchandiser yang bisa approve") if self.env.user.is_leader or self.env.user.is_purchasing_manager: raise UserError("Bisa langsung Confirm") elif self.total_percent_margin == self.total_so_percent_margin and self.sale_order_id: diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index f8127d8c..c1c2c267 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -78,6 +78,7 @@ class SaleOrder(models.Model): payment_link_midtrans = fields.Char(string='Payment Link', help='Url payment yg digenerate oleh midtrans, harap diserahkan ke customer agar dapat dilakukan pembayaran secara mandiri') payment_qr_code = fields.Binary("Payment QR Code") due_id = fields.Many2one('due.extension', string="Due Extension", readonly=True, tracking=True) + vendor_approval_id = fields.Many2one('vendor.approval', string="Vendor Approval", readonly=True, tracking=True) customer_type = fields.Selection([ ('pkp', 'PKP'), ('nonpkp', 'Non PKP') @@ -104,6 +105,7 @@ class SaleOrder(models.Model): ('cust_procurement', 'Customer Procurement') ], string='Web Approval', copy=False) compute_fullfillment = fields.Boolean(string='Compute Fullfillment', compute="_compute_fullfillment") + vendor_approval = fields.Boolean(string='Vendor Approval') note_ekspedisi = fields.Char(string="Note Ekspedisi") date_kirim_ril = fields.Datetime(string='Tanggal Kirim SJ', compute='_compute_date_kirim', copy=False) date_status_done = fields.Datetime(string='Date Done DO', compute='_compute_date_kirim', copy=False) @@ -133,59 +135,105 @@ 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) - def action_estimate_shipping(self): + total_weight = fields.Float(string='Total Weight', compute='_compute_total_weight') + + def _compute_total_weight(self): total_weight = 0 missing_weight_products = [] for line in self.order_line: if line.weight: - total_weight += line.weight + total_weight += line.weight * line.product_uom_qty + + self.total_weight = total_weight + + def action_indoteknik_estimate_shipping(self): + if not self.real_shipping_id.kota_id.is_jabodetabek: + raise UserError('Estimasi ongkir hanya bisa dilakukan di kota Jabodetabek') + + total_weight = 0 + missing_weight_products = [] + + for line in self.order_line: + if line.weight: + total_weight += line.weight * line.product_uom_qty line.product_id.weight = line.weight else: missing_weight_products.append(line.product_id.name) if missing_weight_products: - product_names = '\n'.join(missing_weight_products) - self.message_post(body=f"Produk berikut tidak memiliki berat: \n{product_names}") + product_names = '<br/>'.join(missing_weight_products) + self.message_post(body=f"Produk berikut tidak memiliki berat:<br/>{product_names}") + + if total_weight == 0: + raise UserError("Tidak dapat mengestimasi ongkir tanpa berat yang valid.") + + if total_weight < 10: + total_weight = 10 + self.delivery_amt = total_weight * 3000 + + def action_estimate_shipping(self): + if self.carrier_id.id in [1, 151]: + self.action_indoteknik_estimate_shipping() + return + total_weight = 0 + missing_weight_products = [] + for line in self.order_line: + if line.weight: + total_weight += line.weight * line.product_uom_qty + line.product_id.weight = line.weight + else: + missing_weight_products.append(line.product_id.name) + + if missing_weight_products: + product_names = '<br/>'.join(missing_weight_products) + self.message_post(body=f"Produk berikut tidak memiliki berat:<br/>{product_names}") if total_weight == 0: raise UserError("Tidak dapat mengestimasi ongkir tanpa berat yang valid.") # 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 - - 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) + destination_subsdistrict_id = self.real_shipping_id.kecamatan_id.rajaongkir_id - 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, @@ -211,7 +259,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) @@ -227,14 +275,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 @@ -682,10 +733,14 @@ class SaleOrder(models.Model): for order in self: order.order_line.validate_line() + term_days = 0 + for term_line in order.payment_term_id.line_ids: + term_days += term_line.days + partner = order.partner_id.parent_id or order.partner_id if not partner.property_payment_term_id: raise UserError("Payment Term pada Master Data Customer harus diisi") - if not partner.active_limit: + if not partner.active_limit and term_days > 0: raise UserError("Credit Limit pada Master Data Customer harus diisi") if order.payment_term_id != partner.property_payment_term_id: raise UserError("Payment Term berbeda pada Master Data Customer") @@ -699,16 +754,23 @@ class SaleOrder(models.Model): raise UserError("Salesperson sudah tidak aktif, mohon diisi yang benar pada data SO dan Contact") def sale_order_approve(self): + if self.validate_different_vendor() and not self.vendor_approval and not self.vendor_approval_id: + return self._create_notification_action('Notification', 'Terdapat Vendor yang berbeda dengan MD Vendor') self.check_due() self._validate_order() for order in self: order.order_line.validate_line() + + term_days = 0 + for term_line in order.payment_term_id.line_ids: + term_days += term_line.days + partner = order.partner_id.parent_id or order.partner_id if not partner.property_payment_term_id: raise UserError("Payment Term pada Master Data Customer harus diisi") - if not partner.active_limit: + if not partner.active_limit and term_days > 0: raise UserError("Credit Limit pada Master Data Customer harus diisi") if order.payment_term_id != partner.property_payment_term_id: raise UserError("Payment Term berbeda pada Master Data Customer") @@ -802,9 +864,53 @@ class SaleOrder(models.Model): 'body_html': email_body, 'email_to': salesperson_email, }).send() + + 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 different_vendor: + self.env['vendor.approval.line'].create({ + 'vendor_approval_id': vendor_approval.id, + 'product_id': line.product_id.id, + 'product_uom_qty': line.product_uom_qty, + 'vendor_id': line.vendor_id.id, + '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: + if self.validate_different_vendor() and not self.vendor_approval and not self.vendor_approval_id: + return self._create_notification_action('Notification', 'Terdapat Vendor yang berbeda dengan MD Vendor') + order.check_data_real_delivery_address() order.sale_order_check_approve() order._validate_order() diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 14bb8c99..59ac1ad4 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -14,7 +14,9 @@ class SaleOrderLine(models.Model): states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]" ) + vendor_md_id = fields.Many2one('res.partner', string='MD Vendor') purchase_price = fields.Float('Purchase', required=True, digits='Product Price', default=0.0) + purchase_price_md = fields.Float('MD Purchase') purchase_tax_id = fields.Many2one('account.tax', string='Tax', domain=['|', ('active', '=', False), ('active', '=', True)]) delivery_amt_line = fields.Float('DeliveryAmtLine', compute='compute_delivery_amt_line') fee_third_party_line = fields.Float('FeeThirdPartyLine', compute='compute_fee_third_party_line', default=0) @@ -33,6 +35,7 @@ class SaleOrderLine(models.Model): item_percent_margin_without_deduction = fields.Float('%Margin', compute='_compute_item_margin_without_deduction') weight = fields.Float(string='Weight') md_vendor_id = fields.Many2one('res.partner', string='MD Vendor', readonly=True) + margin_md = fields.Float(string='Margin MD') @api.constrains('note_procurement') def note_procurement_to_apo(self): @@ -126,6 +129,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 @@ -247,8 +253,10 @@ class SaleOrderLine(models.Model): price, taxes, vendor_id = self._get_purchase_price(line.product_id) line.vendor_id = vendor_id line.md_vendor_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_md = price line.purchase_price = price line.purchase_tax_id = taxes diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 6f038386..14190474 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -125,7 +125,9 @@ class StockPicking(models.Model): raise UserError('Hanya Logistic yang bisa mengubah shipping method') def do_unreserve(self): - if not self._context.get('darimana') == 'sale.order': + group_id = self.env.ref('indoteknik_custom.group_role_it').id + users_in_group = self.env['res.users'].search([('groups_id', 'in', [group_id])]) + if not self._context.get('darimana') == 'sale.order' and self.env.user.id not in users_in_group.mapped('id'): self.sale_id.unreserve_id = self.id return self._create_approval_notification('Logistic') diff --git a/indoteknik_custom/models/vendor_approval.py b/indoteknik_custom/models/vendor_approval.py new file mode 100644 index 00000000..e540b8fc --- /dev/null +++ b/indoteknik_custom/models/vendor_approval.py @@ -0,0 +1,73 @@ +from odoo import models, api, fields +from odoo.exceptions import AccessError, UserError, ValidationError +from datetime import timedelta, date +import logging + +_logger = logging.getLogger(__name__) + +class VendorApproval(models.Model): + _name = "vendor.approval" + _description = "Vendor Approval" + _inherit = ['mail.thread'] + _rec_name = 'number' + + number = fields.Char(string='Document No', index=True, copy=False, readonly=True, tracking=True) + 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', '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': + raise UserError('Vendor Approval tidak bisa didelete') + return res + + +class VendorApprovalLine(models.Model): + _name = 'vendor.approval.line' + _description = 'Vendor Approval Line' + _order = 'vendor_approval_id, id' + + vendor_approval_id = fields.Many2one('vendor.approval', string='Vendor Approval Ref', required=True, ondelete='cascade', index=True, copy=False) + product_id = fields.Many2one('product.product', string='Product') + 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') + 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..76b192c5 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -173,13 +173,12 @@ class WebsiteUserCart(models.Model): } return result - def action_mail_reminder_to_checkout(self, limit=10): - user_ids = self.search([]).mapped('user_id')[:limit] + def action_mail_reminder_to_checkout(self, limit=250): + user_ids = self.search([('is_reminder', '=', False)]).mapped('user_id')[:limit] for user in user_ids: latest_cart = self.search([('user_id', '=', user.id), ('is_reminder', '=', False)], order='create_date desc', limit=1) - # Proses semua keranjang untuk user tersebut carts_to_remind = self.search([('user_id', '=', user.id)]) if latest_cart and not latest_cart.is_reminder: @@ -191,11 +190,9 @@ class WebsiteUserCart(models.Model): cart.is_selected = False cart.is_reminder = True - # Mengirim email pengingat untuk keranjang terbaru template = self.env.ref('indoteknik_custom.mail_template_user_cart_reminder_to_checkout') template.send_mail(latest_cart.id, force_send=True) - def calculate_discount(self, user_id): carts = self.search([('user_id', '=', user_id)]) voucher = self.env['voucher'].browse(146) diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 84147e04..80ae0afa 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -139,3 +139,6 @@ access_approval_date_doc,access.approval.date.doc,model_approval_date_doc,,1,1,1 access_account_tax,access.account.tax,model_account_tax,,1,1,1,1 access_approval_unreserve,access.approval.unreserve,model_approval_unreserve,,1,1,1,1 access_approval_unreserve_line,access.approval.unreserve.line,model_approval_unreserve_line,,1,1,1,1 +access_vendor_approval,access.vendor.approval,model_vendor_approval,,1,1,1,1 +access_vendor_approval_line,access.vendor.approval.line,model_vendor_approval_line,,1,1,1,1 +access_vit_kota,access.vit.kota,model_vit_kota,,1,1,1,1 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 1c75c96a..895b242c 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,6 +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" optional="hide"/> <field name="purchase_price" attrs=" { 'readonly': [ @@ -126,13 +129,15 @@ ] } "/> + <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"/> <field name="md_vendor_id" string="MD Vendor" readonly="1" optional="hide"/> diff --git a/indoteknik_custom/views/vendor_approval.xml b/indoteknik_custom/views/vendor_approval.xml new file mode 100644 index 00000000..605edfbf --- /dev/null +++ b/indoteknik_custom/views/vendor_approval.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8"?> +<odoo> + <data> + <record id="vendor_approval_tree" model="ir.ui.view"> + <field name="name">vendor.approval.tree</field> + <field name="model">vendor.approval</field> + <field name="arch" type="xml"> + <tree default_order="create_date desc" create="0"> + <field name="number"/> + <field name="create_date_so"/> + <field name="order_id"/> + <field name="partner_id"/> + <field name="state"/> + </tree> + </field> + </record> + + <record id="vendor_approval_line_tree" model="ir.ui.view"> + <field name="name">vendor.approval.line.tree</field> + <field name="model">vendor.approval.line</field> + <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> + + <record id="vendor_approval_form" model="ir.ui.view"> + <field name="name">vendor.approval.form</field> + <field name="model">vendor.approval</field> + <field name="arch" type="xml"> + <form create="false"> + <header> + <button name="action_approve" + string="Approve" + type="object" + attrs="{'invisible': [('state', 'not in', ['draft'])]}" + /> + <button name="action_reject" + string="Reject" + type="object" + attrs="{'invisible': [('state', 'not in', ['draft'])]}" + /> + </header> + <sheet> + <group> + <group> + <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> + <page string="SO Line"> + <field name="vendor_approval_line" readonly="1"/> + </page> + </notebook> + </sheet> + <div class="oe_chatter"> + <field name="message_follower_ids" widget="mail_followers"/> + <field name="message_ids" widget="mail_thread"/> + </div> + </form> + </field> + </record> + + <record id="vendor_approval_view_search" model="ir.ui.view"> + <field name="name">vendor.approval.search.view</field> <!-- Made the name more descriptive --> + <field name="model">vendor.approval</field> + <field name="arch" type="xml"> + <search string="Search Vendor Approval"> + <field name="number"/> + <field name="partner_id"/> + <field name="order_id"/> + </search> + </field> + </record> + + <record id="vendor_approval_action" model="ir.actions.act_window"> + <field name="name">Vendor Approval</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">vendor.approval</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem + id="menu_vendor_approval" + name="Vendor Approval" + parent="sale.product_menu_catalog" + sequence="4" + action="vendor_approval_action" + /> + </data> +</odoo> diff --git a/indoteknik_custom/views/vit_kota.xml b/indoteknik_custom/views/vit_kota.xml index 97c7e66c..58c97eb4 100755 --- a/indoteknik_custom/views/vit_kota.xml +++ b/indoteknik_custom/views/vit_kota.xml @@ -9,6 +9,7 @@ <field name="name"/> <field name="jenis"/> <field name="state_id"/> + <field name="is_jabodetabek"/> </tree> </field> </record> @@ -28,6 +29,7 @@ <group> <field name="jenis"/> <field name="state_id"/> + <field name="is_jabodetabek"/> </group> <group/> </group> |
