diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-07-13 09:50:57 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-07-13 09:50:57 +0700 |
| commit | 32bf7b115ec71e72d9cde58bfa3c0304c4b1ffcb (patch) | |
| tree | 19257db60cdd44a5527825825ab0032a2693f74d | |
| parent | 3085bfa4333cbc99ed4a0e432c8313cf7009cd2a (diff) | |
| parent | 604ef36b09c2eb2cf89f5b592ab775ba87e0ce88 (diff) | |
Merge remote-tracking branch 'origin/staging' into real-stock
21 files changed, 517 insertions, 26 deletions
diff --git a/indoteknik_api/controllers/api_v1/__init__.py b/indoteknik_api/controllers/api_v1/__init__.py index d05cdf3a..2afefb34 100644 --- a/indoteknik_api/controllers/api_v1/__init__.py +++ b/indoteknik_api/controllers/api_v1/__init__.py @@ -1,3 +1,4 @@ +from . import activity from . import banner from . import blog from . import cart diff --git a/indoteknik_api/controllers/api_v1/activity.py b/indoteknik_api/controllers/api_v1/activity.py new file mode 100644 index 00000000..142db845 --- /dev/null +++ b/indoteknik_api/controllers/api_v1/activity.py @@ -0,0 +1,18 @@ +from .. import controller +from odoo import http +from odoo.http import request + + +class Activity(controller.Controller): + @http.route('/api/v1/activity', auth='public', csrf=False, methods=['POST', 'OPTIONS']) + @controller.Controller.must_authorized() + def create_user_activity(self, **kw): + user_data = self.verify_user_token() + user_id = user_data['user_id'] if user_data else False + request.env['user.activity.log'].create({ + 'page_title': kw.get('page_title', ''), + 'url': kw.get('url', ''), + 'res_user_id': user_id, + 'ip_address': kw.get('ip_address', '') + }) + return self.response(True)
\ No newline at end of file diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 671ff5a8..aa211b75 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -153,6 +153,7 @@ class SaleOrder(controller.Controller): sale_order = request.env['sale.order'].search(domain) if sale_order: sale_order.partner_purchase_order_name = params['value']['name'] + sale_order.client_order_ref = params['value']['name'] sale_order.partner_purchase_order_file = params['value']['file'] data = sale_order.id return self.response(data) @@ -265,6 +266,8 @@ class SaleOrder(controller.Controller): 'shipping_paid_by': 'customer', 'carrier_id': params['value']['carrier_id'], 'delivery_service_type': params['value']['delivery_service_type'], + 'customer_type': 'nonpkp', + 'npwp': '0' } if params['value']['type'] == 'sale_order': parameters['approval_status'] = 'pengajuan1' diff --git a/indoteknik_api/controllers/controller.py b/indoteknik_api/controllers/controller.py index 90bc50ed..0fcf4814 100644 --- a/indoteknik_api/controllers/controller.py +++ b/indoteknik_api/controllers/controller.py @@ -108,7 +108,6 @@ class Controller(http.Controller): return time def response(self, data=[], code=200, description='OK', headers=[]): - request.env['user.activity.log'].record_activity() response = { 'status': { 'code': code, @@ -169,6 +168,12 @@ class Controller(http.Controller): def get_api_token(self, **kw): return self.response(request.env['ir.config_parameter'].sudo().get_param('rest_api_token') or '') + @http.route('/api/ip-address', auth='public', methods=['GET', 'OPTIONS']) + def get_ip_address(self): + address = request.httprequest.remote_addr + address = address if address != '127.0.0.1' else False + return self.response(address) + @http.route('/api/image/<model>/<field>/<id>', auth='public', methods=['GET']) def get_image(self, model, field, id): model = request.env[model].sudo().search([('id', '=', id)], limit=1) diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index 14fe68cb..edf95a58 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -10,6 +10,8 @@ class ProductProduct(models.Model): product_pricelist_default_discount_id = self.env['ir.config_parameter'].get_param('product.pricelist.default_discount_id') product_pricelist_default_discount_id = int(product_pricelist_default_discount_id) product_template = product_product.product_tmpl_id + stock = product_product.qty_stock_vendor + stock = stock if stock > 0 else 1 data = { 'id': product_product.id, 'parent': { @@ -20,7 +22,7 @@ class ProductProduct(models.Model): 'code': product_product.default_code or '', 'name': product_product.display_name, 'price': self.env['product.pricelist'].compute_price(product_pricelist_default_discount_id, product_product.id), - 'stock': product_product.qty_stock_vendor, + 'stock': stock, 'weight': product_product.weight, 'attributes': [x.name for x in product_product.product_template_attribute_value_ids], 'manufacture' : self.api_manufacture(product_product) @@ -61,6 +63,8 @@ class ProductProduct(models.Model): price_discount = flashsale_price discount_percentage = flashsale_discount + stock = product_product.qty_stock_vendor + stock = stock if stock > 0 else 1 product_template = product_product.product_tmpl_id data = { 'id': product_product.id, @@ -76,7 +80,7 @@ class ProductProduct(models.Model): 'discount_percentage': discount_percentage, 'price_discount': price_discount }, - 'stock': product_product.qty_stock_vendor, + 'stock': stock, 'weight': product_product.weight, 'attributes': [x.name for x in product_product.product_template_attribute_value_ids], 'manufacture' : self.api_manufacture(product_product) diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index bba38a53..11921285 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -45,6 +45,7 @@ 'views/uangmuka_penjualan.xml', 'views/sale_order.xml', 'views/account_asset_views.xml', + 'views/account_move_views.xml', 'views/ir_sequence.xml', 'views/stock_location.xml', 'views/stock_picking.xml', diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 8fd33b4a..4af46dae 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -65,3 +65,4 @@ from . import manufacturing from . import requisition from . import token_storage from . import product_sla +from . import account_move_due_extension diff --git a/indoteknik_custom/models/account_move_due_extension.py b/indoteknik_custom/models/account_move_due_extension.py new file mode 100644 index 00000000..1e3bdad1 --- /dev/null +++ b/indoteknik_custom/models/account_move_due_extension.py @@ -0,0 +1,161 @@ +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 DueExtension(models.Model): + _name = "due.extension" + _description = "Due Extension" + _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) + due_line = fields.One2many('due.extension.line', 'due_id', string='Due Extension Lines', auto_join=True) + old_due = fields.Date(string="Old Due") + description = fields.Text(string="Description") + is_approve = fields.Boolean(string="Is Approve", readonly=True, tracking=True) + approval_status = fields.Selection([ + ('pengajuan', 'Pengajuan'), + ('approved', 'Approved'), + ], string='Approval Status', readonly=True, copy=False, index=True, tracking=3) + day_extension = fields.Selection([ + ('3', '3 Hari'), + ('7', '7 Hari'), + ('14', '14 Hari'), + ], string='Day Extension', help='Menambah Due Date yang sudah limit dari hari ini', tracking=True) + counter = fields.Integer(string="Counter", compute='_compute_counter') + + def _compute_counter(self): + for due in self: + due.counter = due.partner_id.counter + + @api.model + def create(self, vals): + vals['number'] = self.env['ir.sequence'].next_by_code('due.extension') or '0' + result = super(DueExtension, self).create(vals) + return result + + def due_extension_approval(self): + if not self.approval_status: + self.approval_status = 'pengajuan' + elif self.approval_status == 'pengajuan': + raise UserError('Anda sudah mengajukan ask approval') + elif self.approval_status == 'approved': + raise UserError('Document sudah di approve') + + def due_extension_cancel(self): + if self.env.user.is_accounting: + if not self.approval_status or self.approval_status == 'pengajuan': + self.approval_status = False + sales = self.env['sale.order'].search([ + ('id', '=', self.order_id.id) + ]) + + sales.action_cancel() + elif self.approval_status == 'approved': + raise UserError('Document sudah di approve, Tidak bisa di cancel') + else: + raise UserError('Hanya Finance yang bisa cancel') + + def approve_new_due(self): + if self.env.user.is_accounting: + if not self.approval_status == 'approved': + self.is_approve = True + self.approval_status = 'approved' + + self.partner_id.counter+=1 + + if self.partner_id: + if self.day_extension: + day_extension = int(self.day_extension) + new_due = date.today() + timedelta(days=day_extension) + + for line in self.due_line: + line.invoice_id.invoice_date_due = new_due + + if self.order_id._notification_margin_leader(): + self.order_id.approval_status = 'pengajuan2' + return self.order_id._notification_has_margin_leader() + + if self.order_id._notification_margin_manager(): + self.order_id.approval_status = 'pengajuan1' + return self.order_id._notification_has_margin_manager() + + sales = self.env['sale.order'].search([ + ('id', '=', self.order_id.id) + ]) + + # sales.state = 'sale' + sales.action_confirm() + self.order_id.due_id = self.id + else: + raise UserError('Document ini sudah di approve') + else: + raise UserError('Hanya Finance Yang Bisa Approve') + + def generate_due_line(self): + partners = [] + partners += self.partner_id.child_ids + partners.append(self.partner_id) + + + for partner in partners: + query = [ + ('partner_id', '=', partner.id), + ('state', '=', 'posted'), + ('move_type', '=', 'out_invoice'), + ('amount_residual_signed', '>', 0) + ] + invoices = self.env['account.move'].search(query, order='invoice_date') + count = 0 + + for invoice in invoices: + if invoice.invoice_day_to_due < 0: + self.env['due.extension.line'].create([{ + 'due_id': self.id, + 'partner_id': invoice.partner_id.id, + 'invoice_id': invoice.id, + 'date_invoice': invoice.invoice_date, + 'efaktur_id': invoice.efaktur_id.id, + 'reference': invoice.ref, + 'total_amt': invoice.amount_total, + 'open_amt': invoice.amount_residual_signed, + 'due_date': invoice.invoice_date_due + }]) + count += 1 + _logger.info("Due Extension Line generated %s" % count) + def unlink(self): + res = super(DueExtension, self).unlink() + if not self._name == 'due.extension': + raise UserError('Due Extension tidak bisa didelete') + return res + + +class DueExtensionLine(models.Model): + _name = 'due.extension.line' + _description = 'Due Extension Line' + _order = 'due_id, id' + + due_id = fields.Many2one('due.extension', string='Due Ref', required=True, ondelete='cascade', index=True, copy=False) + partner_id = fields.Many2one('res.partner', string='Customer') + invoice_id = fields.Many2one('account.move', string='Invoice') + date_invoice = fields.Date(string='Invoice Date') + efaktur_id = fields.Many2one('vit.efaktur', string='Faktur Pajak') + reference = fields.Char(string='Reference') + total_amt = fields.Float(string='Total Amount') + open_amt = fields.Float(string='Open Amount') + due_date = fields.Date(string='Due Date', compute="_compute_due_date") + day_to_due = fields.Integer(string='Day To Due', compute="_compute_day_to_due") + + def _compute_day_to_due(self): + for line in self: + line.day_to_due = line.invoice_id.invoice_day_to_due + + def _compute_due_date(self): + for line in self: + line.due_date = line.invoice_id.invoice_date_due + diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index 87319bf6..e21b411d 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -59,11 +59,18 @@ class AutomaticPurchase(models.Model): # new_po = self.env['purchase.order'].create([param_header]) brand_id = product.brand_id.id count += 10 + + qty_available = product.product_id.qty_onhand_bandengan + product.product_id.qty_incoming_bandengan - product.product_id.outgoing_qty + suggest = 'harus beli' + if qty_available > product.qty_purchase: + suggest = 'masih cukup' param_line = { 'order_id': new_po.id, 'sequence': count, 'product_id': product.product_id.id, 'product_qty': product.qty_purchase, + 'qty_available_store': qty_available, + 'suggest': suggest, 'product_uom_qty': product.qty_purchase, 'price_unit': product.last_price, } diff --git a/indoteknik_custom/models/delivery_order.py b/indoteknik_custom/models/delivery_order.py index 3f8da384..be5fd2e0 100644 --- a/indoteknik_custom/models/delivery_order.py +++ b/indoteknik_custom/models/delivery_order.py @@ -74,6 +74,7 @@ class DeliveryOrderLine(models.TransientModel): carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method') tracking_no = fields.Char(string='Tracking No') delivery_order_id = fields.Many2one('delivery.order', string='Delivery Order') + partner_id = fields.Many2one('res.partner', string='Customer') @api.onchange('name') def onchange_name(self): @@ -98,6 +99,8 @@ class DeliveryOrderLine(models.TransientModel): self.tracking_no = picking.delivery_tracking_no + self.partner_id = picking.partner_id + delivery_type = self.get_delivery_type(picking.driver_departure_date, picking.driver_arrival_date) if delivery_type != 'departure': self.departure_date = picking.driver_departure_date.astimezone(timezone('Asia/Jakarta')).strftime('%Y-%m-%d %H:%M:%S') diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 13ff2931..7091bb72 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -191,6 +191,9 @@ class PurchaseOrder(models.Model): raise UserError("Beda Margin dengan Sales, harus approval Manager") if not self.sale_order_id and not self.env.user.is_purchasing_manager and not self.env.user.is_leader: raise UserError("Tidak ada link dengan SO, harus approval Manager") + for line in self.order_line: + if not line.product_id.purchase_ok: + raise UserError("Terdapat barang yang tidak bisa di proses") self.approval_status = 'approved' self.po_status = 'menunggu' @@ -212,6 +215,16 @@ class PurchaseOrder(models.Model): else: self.approval_status = 'pengajuan1' + def re_calculate(self): + for line in self.order_line: + sale_order_line = self.env['sale.order.line'].search([ + ('product_id', '=', line.product_id.id), + ('order_id', '=', line.order_id.sale_order_id.id) + ], limit=1, order='price_reduce_taxexcl') + for so_line in sale_order_line: + unit_price = line.price_unit + so_line.purchase_price = unit_price + def button_cancel(self): res = super(PurchaseOrder, self).button_cancel() self.approval_status = False diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index 77abaaf9..5dec8da8 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -13,6 +13,12 @@ class ResPartner(models.Model): company_type_id = fields.Many2one('res.partner.company_type', string='Company Type') custom_pricelist_id = fields.Many2one('product.pricelist', string='Price Matrix') group_partner_id = fields.Many2one('group.partner', string='Group Partner') + customer_type = fields.Selection([ + ('pkp', 'PKP'), + ('nonpkp', 'Non PKP') + ]) + sppkp = fields.Char(string="SPPKP") + counter = fields.Integer(string="Counter", default=0) def unlink(self): if self._name == 'res.partner': diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 0a794f6d..5a3cada9 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -78,6 +78,21 @@ class SaleOrder(models.Model): delivery_service_type = fields.Char(string='Delivery Service Type', help='data dari rajaongkir') grand_total = fields.Monetary(string='Grand Total', help='Amount total + amount delivery', compute='_compute_grand_total') 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') + due_id = fields.Many2one('due.extension', string="Due Extension", readonly=True, tracking=True) + customer_type = fields.Selection([ + ('pkp', 'PKP'), + ('nonpkp', 'Non PKP') + ]) + sppkp = fields.Char(string="SPPKP") + npwp = fields.Char(string="NPWP") + purchase_total = fields.Monetary(string='Purchase Total', compute='_compute_purchase_total') + + def _compute_purchase_total(self): + for order in self: + total = 0 + for line in order.order_line: + total += line.vendor_subtotal + order.purchase_total = total def generate_payment_link_midtrans_sales_order(self): # midtrans_url = 'https://app.sandbox.midtrans.com/snap/v1/transactions' # dev - sandbox @@ -217,6 +232,15 @@ class SaleOrder(models.Model): def onchange_partner_shipping(self): self.real_shipping_id = self.partner_shipping_id + @api.onchange('partner_id') + def onchange_partner_contact(self): + parent_id = self.partner_id.parent_id + parent_id = parent_id if parent_id else self.partner_id + + self.npwp = parent_id.npwp + self.sppkp = parent_id.sppkp + self.customer_type = parent_id.customer_type + def _get_purchases(self): po_state = ['done', 'draft', 'purchase'] for order in self: @@ -292,6 +316,7 @@ class SaleOrder(models.Model): def sale_order_approve(self): # raise UserError("Bisa langsung Confirm") self.check_due() + for order in self: if order.warehouse_id.id != 8: #GD Bandengan raise UserError('Gudang harus Bandengan') @@ -324,16 +349,20 @@ class SaleOrder(models.Model): # must add product can sell validation if not line.product_id.product_tmpl_id.sale_ok: raise UserError('Product %s belum bisa dijual, harap hubungi finance' % line.product_id.display_name) - if line.product_id.id == 232383: + if line.product_id.id == 224484: raise UserError(_('Tidak bisa Confirm menggunakan Produk Sementara')) if not line.vendor_id or not line.purchase_price: raise UserError(_('Isi Vendor dan Harga Beli sebelum Request Approval')) - if order.total_percent_margin <= 15 and not self.env.user.is_leader: + + if order.validate_partner_invoice_due(): + return self._notification_has_unapprove_due() + + if order._notification_margin_leader(): order.approval_status = 'pengajuan2' - elif order.total_percent_margin <= 22 and not self.env.user.is_leader and not self.env.user.is_sales_manager: - order.approval_status = 'pengajuan1' - elif order._have_outstanding_invoices() and not self.env.user.is_leader and not self.env.user.is_sales_manager: + return self._notification_has_margin_leader() + elif order._notification_margin_manager(): order.approval_status = 'pengajuan1' + return self._notification_has_margin_manager() else: raise UserError("Bisa langsung Confirm") @@ -350,10 +379,91 @@ class SaleOrder(models.Model): # raise UserError("PO harus di Cancel dahulu") self.approval_status = False + self.due_id = False return super(SaleOrder, self).action_cancel() + + def validate_partner_invoice_due(self): + parent_id = self.partner_id.parent_id.id + parent_id = parent_id if parent_id else self.partner_id.id + + if self.due_id and self.due_id.is_approve == False: + raise UserError('Document Over Due Yang Anda Buat Belum Di Approve') + + if not self.env.user.is_leader and not self.env.user.is_sales_manager: + query = [ + ('partner_id', '=', parent_id), + ('state', '=', 'posted'), + ('move_type', '=', 'out_invoice'), + ('amount_residual_signed', '>', 0) + ] + invoices = self.env['account.move'].search(query, order='invoice_date') + due_extension = self.env['due.extension'].create([{ + 'partner_id': parent_id, + 'day_extension': '3', + 'order_id': self.id, + }]) + due_extension.generate_due_line() + self.due_id = due_extension.id + if len(self.due_id.due_line) > 0: + return True + else: + due_extension.unlink() + return False + + def _notification_margin_leader(self): + if self.total_percent_margin <= 15 and not self.env.user.is_leader: + return True + else: + return False + + def _notification_margin_manager(self): + if self.total_percent_margin <= 22 and not self.env.user.is_leader and not self.env.user.is_sales_manager: + return True + else: + return False + + def _notification_has_unapprove_due(self): + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': 'Notification', + 'message': 'Ada Invoice Yang Sudah Over Due, Silahkan Memperbarui Over Due di Due Extension', + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + + def _notification_has_margin_leader(self): + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': 'Notification', + 'message': 'SO Harus Di Approve Oleh Pimpinan', + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + + def _notification_has_margin_manager(self): + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'title': 'Notification', + 'message': 'SO Harus Di Approve Oleh Sales Manager', + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + + def _set_sppkp_npwp_contact(self): + parent_id = self.partner_id.parent_id + parent_id = parent_id if parent_id else self.partner_id + parent_id.customer_type = self.customer_type + parent_id.npwp = self.npwp + parent_id.sppkp = self.sppkp + def action_confirm(self): - res = super(SaleOrder, self).action_confirm() for order in self: if order.warehouse_id.id != 8: #GD Bandengan raise UserError('Gudang harus Bandengan') @@ -372,16 +482,20 @@ class SaleOrder(models.Model): raise UserError(_('Tidak bisa Confirm menggunakan Produk Sementara')) if not line.vendor_id or not line.purchase_price or not line.purchase_tax_id: raise UserError(_('Isi Vendor, Harga Beli, dan Tax sebelum Request Approval')) - if order.total_percent_margin <= 15 and not self.env.user.is_leader: - raise UserError("Harus diapprove oleh Pimpinan") - elif order.total_percent_margin <= 22 and not self.env.user.is_leader and not self.env.user.is_sales_manager: - raise UserError("Harus diapprove oleh Manager") - elif order._have_outstanding_invoices() and not self.env.user.is_leader and not self.env.user.is_sales_manager: - raise UserError("Ada invoice due date, harus diapprove oleh Manager") + + if order.validate_partner_invoice_due(): + return self._notification_has_unapprove_due() + + if order._notification_margin_leader(): + return self._notification_has_margin_leader() + elif order._notification_margin_manager(): + return self._notification_has_margin_manager() else: order.approval_status = 'approved' - order.calculate_line_no() + order._set_sppkp_npwp_contact() + order.calculate_line_no() + res = super(SaleOrder, self).action_confirm() return res def _have_outstanding_invoices(self): @@ -462,7 +576,7 @@ class SaleOrderLine(models.Model): 'res.partner', string='Vendor', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, change_default=True, index=True, tracking=1, - domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", ) + domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",) purchase_price = fields.Float('Purchase', required=True, digits='Product Price', default=0.0) purchase_tax_id = fields.Many2one('account.tax', string='Tax', domain=['|', ('active', '=', False), ('active', '=', True)]) @@ -470,6 +584,23 @@ class SaleOrderLine(models.Model): fee_third_party_line = fields.Float('FeeThirdPartyLine', compute='compute_fee_third_party_line', default=0) line_no = fields.Integer('No', default=0, copy=False) note_procurement = fields.Char(string='Note', help="Harap diisi jika ada keterangan tambahan dari Procurement, agar dapat dimonitoring") + vendor_subtotal = fields.Float(string='Vendor Subtotal', compute="_compute_vendor_subtotal") + + def _compute_vendor_subtotal(self): + for line in self: + if line.purchase_price > 0 and line.product_uom_qty > 0: + # product = line.product_id + + # if product: + # vendor_price = line.purchase_price + # if line.purchase_tax_id.price_include: + # vendor_price = line.purchase_price + # else: + # vendor_price = line.purchase_price + (line.purchase_price*11/100) + subtotal = line.purchase_price * line.product_uom_qty + line.vendor_subtotal = subtotal + else: + line.vendor_subtotal = 0 def compute_item_margin(self): for line in self: @@ -530,6 +661,7 @@ class SaleOrderLine(models.Model): [('product_id', '=', self.product_id.id)], limit=1, order='product_price ASC') line.vendor_id = purchase_price.vendor_id line.tax_id = line.order_id.sales_tax_id + line.purchase_price = purchase_price.product_price def compute_delivery_amt_line(self): for line in self: diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index a14e71a3..2ddb5f75 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -298,14 +298,14 @@ class StockPicking(models.Model): # continue # raise UserError('Sudah pernah dikirim kalender') - if self.picking_type_id.code == 'outgoing': - for line in self.move_line_ids_without_package: - if line.move_id.sale_line_id.qty_delivered + line.qty_done > line.move_id.sale_line_id.product_uom_qty: - raise UserError("Qty Delivered akan lebih dari Qty SO") - elif self.picking_type_id.code == 'incoming': - for line in self.move_ids_without_package: - if line.purchase_line_id.qty_received + line.quantity_done > line.purchase_line_id.product_qty: - raise UserError('Qty Received akan lebih dari Qty PO') + # if self.picking_type_id.code == 'outgoing': + # for line in self.move_line_ids_without_package: + # if line.move_id.sale_line_id.qty_delivered + line.qty_done > line.move_id.sale_line_id.product_uom_qty: + # raise UserError("Qty Delivered akan lebih dari Qty SO") + # elif self.picking_type_id.code == 'incoming': + # for line in self.move_ids_without_package: + # if line.purchase_line_id.qty_received + line.quantity_done > line.purchase_line_id.product_qty: + # raise UserError('Qty Received akan lebih dari Qty PO') if self.is_internal_use: self.approval_status = 'approved' diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index d809f3c4..a470fa8f 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -1,4 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_due_extension,access.due.extension,model_due_extension,,1,1,1,1 access_x_banner_category,access.x.banner.category,model_x_banner_category,,1,1,1,1 access_x_banner_banner,access.x.banner.banner,model_x_banner_banner,,1,1,1,1 access_x_biaya_kirim,access.x.biaya.kirim,model_x_biaya_kirim,,1,1,1,1 @@ -14,6 +15,7 @@ access_delivery_order,access.delivery.order,model_delivery_order,,1,1,1,1 access_delivery_order_line,access.delivery.order.line,model_delivery_order_line,,1,1,1,1 access_dunning_run,access.dunning.run,model_dunning_run,,1,1,1,1 access_dunning_run_line,access.dunning.run.line,model_dunning_run_line,,1,1,1,1 +access_due_extension_line,access.due.extension.line,model_due_extension_line,,1,1,1,1 access_website_user_cart,access.website.user.cart,model_website_user_cart,,1,1,1,1 access_website_user_wishlist,access.website.user.wishlist,model_website_user_wishlist,,1,1,1,1 access_website_brand_homepage,access.website.brand.homepage,model_website_brand_homepage,,1,1,1,1 diff --git a/indoteknik_custom/views/account_move_views.xml b/indoteknik_custom/views/account_move_views.xml new file mode 100644 index 00000000..983fbd5a --- /dev/null +++ b/indoteknik_custom/views/account_move_views.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<odoo> + <record id="due_extension_tree" model="ir.ui.view"> + <field name="name">due.extension.tree</field> + <field name="model">due.extension</field> + <field name="arch" type="xml"> + <tree create="false"> + <field name="number"/> + <field name="partner_id"/> + <field name="day_extension"/> + <field name="description"/> + <field name="approval_status"/> + <field name="is_approve"/> + </tree> + </field> + </record> + + <record id="due_extension_line_tree" model="ir.ui.view"> + <field name="name">due.extension.line.tree</field> + <field name="model">due.extension.line</field> + <field name="arch" type="xml"> + <tree> + <field name="partner_id"/> + <field name="invoice_id"/> + <field name="date_invoice"/> + <field name="due_date"/> + <field name="day_to_due"/> + <field name="efaktur_id"/> + <field name="reference"/> + <field name="total_amt"/> + <field name="open_amt"/> + </tree> + </field> + </record> + +<record id="due_extension_form" model="ir.ui.view"> + <field name="name">due.extension.form</field> + <field name="model">due.extension</field> + <field name="arch" type="xml"> + <form create="false"> + <header> + <button name="approve_new_due" + string="Approve" + type="object" + /> + <button name="due_extension_approval" + string="Ask Approval" + type="object" + /> + <button name="due_extension_cancel" + string="Cancel" + type="object" + /> + </header> + <sheet> + <group> + <group> + <field name="partner_id" readonly="1"/> + <field name="day_extension" attrs="{'readonly': [('is_approve', '=', True)]}"/> + </group> + <group> + <field name="is_approve" readonly="1"/> + <field name="order_id" readonly="1"/> + <field name="counter" readonly="1"/> + <field name="approval_status" readonly="1"/> + </group> + </group> + <group> + <field name="description" attrs="{'readonly': [('approval_status', '=', 'approved')]}"/> + </group> + <notebook> + <page string="Invoices"> + <field name="due_line" attrs="{'readonly': [('is_approve', '=', True)]}"/> + </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="due_extension_action" model="ir.actions.act_window"> + <field name="name">Due Extension</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">due.extension</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem + id="menu_due_extension" + name="Due Extension" + parent="sale.product_menu_catalog" + sequence="4" + action="due_extension_action" + /> + <menuitem id="menu_due_extension" name="Due Extension" + parent="account.menu_finance_receivables" + action="due_extension_action" + sequence="100" + /> +</odoo> diff --git a/indoteknik_custom/views/delivery_order.xml b/indoteknik_custom/views/delivery_order.xml index 29ca7365..0b2fd576 100644 --- a/indoteknik_custom/views/delivery_order.xml +++ b/indoteknik_custom/views/delivery_order.xml @@ -21,6 +21,7 @@ <field name="arrival_date" readonly="1"/> <field name="carrier_id" readonly="1"/> <field name="tracking_no"/> + <field name="partner_id" readonly="1"/> </tree> </field> </sheet> diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml index 9af85408..a8348772 100644 --- a/indoteknik_custom/views/ir_sequence.xml +++ b/indoteknik_custom/views/ir_sequence.xml @@ -31,6 +31,16 @@ <field name="number_increment">1</field> </record> + <record id="sequence_due_extension" model="ir.sequence"> + <field name="name">Due Extension</field> + <field name="code">due.extension</field> + <field name="active">TRUE</field> + <field name="prefix">DE/%(year)s/</field> + <field name="padding">5</field> + <field name="number_next">1</field> + <field name="number_increment">1</field> + </record> + <record id="sequence_requisition" model="ir.sequence"> <field name="name">Requisition</field> <field name="code">requisition</field> diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml index 5b0c99ef..4efa8cf4 100755 --- a/indoteknik_custom/views/purchase_order.xml +++ b/indoteknik_custom/views/purchase_order.xml @@ -42,6 +42,11 @@ <field name="total_so_margin"/> <field name="total_percent_margin"/> <field name="total_so_percent_margin"/> + <button name="re_calculate" + string="Re Calculate" + type="object" + attrs="{'invisible': [('approval_status', '=', 'approved')]}" + /> </field> <field name="product_id" position="before"> <field name="line_no" attrs="{'readonly': 1}" optional="hide"/> @@ -59,6 +64,8 @@ </page> <field name="fiscal_position_id" position="after"> <field name="note_description"/> + <field name="total_so_percent_margin"/> + </field> </field> </record> diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index a9372da0..d609fdd5 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -6,13 +6,18 @@ <field name="model">res.partner</field> <field name="inherit_id" ref="base.view_partner_form"/> <field name="arch" type="xml"> - <field name="vat" position="after"> + <field name="npwp" position="after"> + <field name="sppkp"/> + <field name="counter"/> <field name="reference_number"/> </field> <field name="industry_id" position="after"> <field name="company_type_id"/> <field name="group_partner_id"/> </field> + <field name="npwp" position="before"> + <field name="customer_type"/> + </field> </field> </record> </data> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 85f687c1..70e3392f 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -27,6 +27,12 @@ <field name="fee_third_party"/> <field name="total_percent_margin"/> </field> + <field name="analytic_account_id" position="after"> + <field name="customer_type" attrs="{'required': ['|', ('create_date', '>', '2023-06-28'), ('create_date', '=', False)]}"/> + <field name="npwp" placeholder='99.999.999.9-999.999' attrs="{'required': ['|', ('create_date', '>', '2023-06-28'), ('create_date', '=', False)]}"/> + <field name="sppkp" attrs="{'invisible': [('customer_type','!=','pkp')], 'required': [('customer_type', '=', 'pkp')]}"/> + <field name="due_id" readonly="1"/> + </field> <field name="partner_shipping_id" position="after"> <field name="real_shipping_id"/> <field name="approval_status" /> @@ -63,6 +69,7 @@ <field name="purchase_tax_id" attrs="{'readonly': [('parent.approval_status', '!=', False)]}" domain="[('type_tax_use','=','purchase')]"/> <field name="item_percent_margin"/> <field name="note_procurement" optional="hide"/> + <field name="vendor_subtotal" optional="hide"/> </xpath> <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_id']" position="before"> <field name="line_no" readonly="1" optional="hide"/> |
