diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-06-15 15:47:05 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-06-15 15:47:05 +0700 |
| commit | 55c67c71b04fce80c635b3a58d91c8bcb02e17c8 (patch) | |
| tree | ed8833b969800e36b887b4134c14dab89d3b91c7 | |
| parent | 1f2995a85428ac4335123bd33d48ae17d3c9f36f (diff) | |
| parent | 24649f8e939484759ef34e5e68f251d951f63c02 (diff) | |
Merge commit '24649f8e939484759ef34e5e68f251d951f63c02'
Conflicts:
indoteknik_custom/__manifest__.py
indoteknik_custom/security/ir.model.access.csv
28 files changed, 699 insertions, 67 deletions
diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 2ac92bf9..35361ba4 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -293,6 +293,11 @@ class SaleOrder(controller.Controller): price = pricelist[price_tier]() discount_key = 'discount_%s' % price_tier if price[discount_key] > 0: discount = price[discount_key] + + flashsale = product._get_flashsale_price() + flashsale_discount = flashsale['flashsale_discount'] + if flashsale_discount > 0 and flashsale_discount > discount: + discount = flashsale_discount parameters.append({ 'company_id': 1, diff --git a/indoteknik_api/models/account_move.py b/indoteknik_api/models/account_move.py index 54e06f84..23a7076c 100644 --- a/indoteknik_api/models/account_move.py +++ b/indoteknik_api/models/account_move.py @@ -6,6 +6,10 @@ class AccountMove(models.Model): _inherit = 'account.move' def api_v1_single_response(self, account_move, context=False): + sale_order = self.env['sale.order'].search([('name', '=', account_move.invoice_origin), ('state', '=', 'done')], limit=1) + amount_residual = account_move.amount_residual + if sale_order.payment_status == 'settlement' or sale_order.payment_status == 'capture': + amount_residual = 0 data = { 'token': self.env['rest.api'].md5_salt(account_move.id, 'account.move'), 'id': account_move.id, @@ -14,7 +18,7 @@ class AccountMove(models.Model): 'payment_term': account_move.invoice_payment_term_id.name or '', 'sales': account_move.invoice_user_id.name, 'amount_total': account_move.amount_total, - 'amount_residual': account_move.amount_residual, + 'amount_residual': amount_residual, 'invoice_date': account_move.invoice_date.strftime('%d/%m/%Y') or '', 'efaktur': True if account_move.efaktur_document else False, } @@ -30,7 +34,7 @@ class AccountMove(models.Model): 'payment_term': account_move.invoice_payment_term_id.name or '', 'sales': account_move.invoice_user_id.name, 'amount_total': account_move.amount_total, - 'amount_residual': account_move.amount_residual, + 'amount_residual': amount_residual, 'invoice_date_due': account_move.invoice_date_due.strftime('%d/%m/%Y') or '', 'customer': res_users.api_address_response(account_move.partner_id), 'products': [], diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index 49ea7804..14fe68cb 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -54,6 +54,13 @@ class ProductProduct(models.Model): if price[discount_key] > 0: discount_percentage = price[discount_key] if price[price_key] > 0: price_discount = price[price_key] + flashsale = product_product._get_flashsale_price() + flashsale_price = flashsale['flashsale_price'] + flashsale_discount = flashsale['flashsale_discount'] + if flashsale_price > 0 and flashsale_price < price_discount: + price_discount = flashsale_price + discount_percentage = flashsale_discount + product_template = product_product.product_tmpl_id data = { 'id': product_product.id, @@ -139,7 +146,7 @@ class ProductProduct(models.Model): default_divide_tax = float(1.11) price_after_disc = self._get_website_price_after_disc() res = price_after_disc / default_divide_tax - res = math.floor(res) + res = math.ceil(res) return res def _get_website_price_after_disc(self): diff --git a/indoteknik_api/models/product_template.py b/indoteknik_api/models/product_template.py index c3df97a5..1a345967 100644 --- a/indoteknik_api/models/product_template.py +++ b/indoteknik_api/models/product_template.py @@ -59,7 +59,6 @@ class ProductTemplate(models.Model): 'image': self.env['ir.attachment'].api_image('product.template', 'image_128', product_template.id), 'code': product_template.default_code or '', 'name': product_template.name, - 'lowest_price': self.env['product.pricelist'].get_lowest_product_variant_price(product_template, product_pricelist_default_discount_id), 'variant_total': len(product_template.product_variant_ids), 'stock_total': product_template.qty_stock_vendor, 'weight': product_template.weight, diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index c116ff0c..f21fab0c 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -74,10 +74,15 @@ 'views/procurement_monitoring_detail.xml', 'views/product_product.xml', 'views/brand_vendor.xml', +<<<<<<< HEAD 'views/promotion_program.xml', 'views/promotion_program_line.xml', 'views/promotion_program_free_item.xml', 'views/promotion_program_keyword.xml', +======= + 'views/requisition.xml', + 'views/landedcost.xml', +>>>>>>> 24649f8e939484759ef34e5e68f251d951f63c02 '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 3123d608..823463ec 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -66,3 +66,4 @@ from . import raja_ongkir from . import procurement_monitoring_detail from . import brand_vendor from . import manufacturing +from . import requisition diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index 56f3e82c..c2e93632 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -33,13 +33,36 @@ class AccountMove(models.Model): return res def action_post(self): + if self._name != 'account.move': + return super(AccountMove, self).action_post() + + # validation cant qty invoice greater than qty order + if self.move_type == 'out_invoice': + query = ["&",("name","=",self.invoice_origin),"|",("state","=","sale"),("state","=","done")] + sale_order = self.env['sale.order'].search(query, limit=1) + sum_qty_invoice = sum_qty_order = 0 + for line in sale_order.order_line: + sum_qty_invoice += line.qty_invoiced + sum_qty_order += line.product_uom_qty + if sum_qty_invoice > sum_qty_order: + raise UserError('Error Qty Invoice akan lebih besar dari Qty Order jika lanjut Posting') + elif self.move_type == 'in_invoice': + query = ["&",("name","=",self.invoice_origin),"|",("state","=","purchase"),("state","=","done")] + purchase_order = self.env['purchase.order'].search(query, limit=1) + sum_qty_invoice = sum_qty_order = 0 + for line in purchase_order.order_line: + sum_qty_invoice += line.qty_invoiced + sum_qty_order += line.product_uom_qty + if sum_qty_invoice > sum_qty_order: + raise UserError('Error Qty Invoice akan lebih besar dari Qty Order jika lanjut Posting') + res = super(AccountMove, self).action_post() # if not self.env.user.is_accounting: # raise UserError('Hanya Accounting yang bisa Posting') - if self._name == 'account.move': - for entry in self: - for line in entry.line_ids: - line.date_maturity = entry.date + # if self._name == 'account.move': + for entry in self: + for line in entry.line_ids: + line.date_maturity = entry.date return res def _compute_invoice_day_to_due(self): diff --git a/indoteknik_custom/models/apache_solr.py b/indoteknik_custom/models/apache_solr.py index a988a8d3..9f187d78 100644 --- a/indoteknik_custom/models/apache_solr.py +++ b/indoteknik_custom/models/apache_solr.py @@ -168,3 +168,12 @@ class ApacheSolr(models.Model): _solr.add(documents) end_time = time.time() _logger.info("[SYNC_PRODUCT_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) + + def _test_product_price(self, product_id=228178): + product = self.env['product.product'].search([('id', '=', product_id)], limit=1) + _logger.info('price incl tax: %s' % product._get_website_price_include_tax()) + _logger.info('price excl tax: %s' % product._get_website_price_exclude_tax()) + _logger.info('discount : %s' % product._get_website_disc(0)) + _logger.info('price after discount : %s' % product._get_website_price_after_disc()) + _logger.info('price excl after discount : %s' % product._get_website_price_after_disc_and_tax()) + _logger.info('tax : %s' % product._get_website_tax()) diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index eea66b99..87319bf6 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -88,7 +88,7 @@ class AutomaticPurchase(models.Model): if point.product_id.virtual_available > point.product_min_qty: continue qty_purchase = point.product_max_qty - point.product_id.virtual_available - po_line = self.env['purchase.order.line'].search([('product_id', '=', point.product_id.id), ('order_id.state', '=', 'done')], limit=1) + po_line = self.env['purchase.order.line'].search([('product_id', '=', point.product_id.id), ('order_id.state', '=', 'done')], order='id desc', limit=1) if self.vendor_id: purchase_price = self.env['purchase.pricelist'].search([ diff --git a/indoteknik_custom/models/crm_lead.py b/indoteknik_custom/models/crm_lead.py index e7af4b1c..b87315ff 100755 --- a/indoteknik_custom/models/crm_lead.py +++ b/indoteknik_custom/models/crm_lead.py @@ -81,7 +81,7 @@ class CrmLead(models.Model): if not lead.partner_id: continue - if not lead.user_id or lead.user_id.id == 2: + if not lead.user_id or lead.user_id.id == 2 or lead.user_id.id == 25: if lead.partner_id.parent_id.user_id: salesperson_id = lead.partner_id.parent_id.user_id.id elif lead.partner_id.user_id: diff --git a/indoteknik_custom/models/manufacturing.py b/indoteknik_custom/models/manufacturing.py index 15756e44..2455a117 100644 --- a/indoteknik_custom/models/manufacturing.py +++ b/indoteknik_custom/models/manufacturing.py @@ -25,8 +25,8 @@ class Manufacturing(models.Model): return super(Manufacturing, self).button_mark_done() for line in self.move_raw_ids: - if line.quantity_done > 0 and line.quantity_done != self.product_uom_qty: - raise UserError('Qty Consume per Line tidak sama dengan Qty to Produce') + # if line.quantity_done > 0 and line.quantity_done != self.product_uom_qty: + # raise UserError('Qty Consume per Line tidak sama dengan Qty to Produce') if line.forecast_availability != line.product_uom_qty: raise UserError('Qty Reserved belum sesuai dengan yang seharusnya') diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index 49235ec7..9c480f4c 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -1,5 +1,6 @@ from odoo import fields, models, api from datetime import datetime, timedelta +from odoo.exceptions import AccessError, UserError, ValidationError import logging _logger = logging.getLogger(__name__) @@ -69,6 +70,10 @@ class ProductTemplate(models.Model): rate += 2 product.virtual_rating = rate + def unlink(self): + if self._name == 'product.template': + raise UserError('Maaf anda tidak bisa delete product') + def update_new_product(self): current_time = datetime.now() delta_time = current_time - timedelta(days=30) @@ -185,6 +190,8 @@ class ProductTemplate(models.Model): product.product_rating = rate product.last_calculate_rating = current_time + + class ProductProduct(models.Model): _inherit = "product.product" @@ -223,3 +230,7 @@ class ProductProduct(models.Model): for product in self: stock_vendor = self.env['stock.vendor'].search([('product_variant_id', '=', product.id)], limit=1) product.qty_stock_vendor = stock_vendor.quantity + product.qty_available + + def unlink(self): + if self._name == 'product.product': + raise UserError('Maaf anda tidak bisa delete product')
\ No newline at end of file diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index ea99e165..7e18bd8f 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -151,6 +151,10 @@ class PurchaseOrder(models.Model): self.order_line.unlink() for order_line in self.sale_order_id.order_line: if order_line.product_id.id and order_line.product_id.id not in products_exception: + # qty_available = self.env['stock.quant'].search([ + # ('product_id', '=', order_line.product_id.id), + # ('location_id', '=', "BU/Stock") + # ], limit=1) qty_available = order_line.product_id.virtual_available suggest = 'harus beli' if order_line.product_id.virtual_available > order_line.product_qty: diff --git a/indoteknik_custom/models/requisition.py b/indoteknik_custom/models/requisition.py new file mode 100644 index 00000000..5bb3272e --- /dev/null +++ b/indoteknik_custom/models/requisition.py @@ -0,0 +1,179 @@ +from odoo import models, fields, api +from odoo.exceptions import UserError +from datetime import datetime +import logging + +_logger = logging.getLogger(__name__) + + +class Requisition(models.Model): + _name = 'requisition' + _order = 'id desc' + + number = fields.Char(string='Document No', index=True, copy=False, readonly=True) + date_doc = fields.Date(string='Date', help='isi tanggal hari ini') + description = fields.Char(string='Description', help='bebas isinya apa aja') + requisition_lines = fields.One2many('requisition.line', 'requisition_id', string='Lines', auto_join=True) + notification = fields.Char(string='Notification') + is_po = fields.Boolean(string='Is PO') + requisition_match = fields.One2many('requisition.purchase.match', 'requisition_id', string='Matches', auto_join=True) + sale_order_id = fields.Many2one('sale.order', string='SO', help='harus diisi nomor SO yang ingin digenerate', + domain="[('state', '=', 'sale')]") + + @api.model + def create(self, vals): + vals['number'] = self.env['ir.sequence'].next_by_code('requisition') or '0' + result = super(Requisition, self).create(vals) + return result + + def create_requisition_from_sales(self): + if self.requisition_lines: + raise UserError('Sudah digenerate sebelumnya, hapus line terlebih dahulu') + if not self.sale_order_id: + raise UserError('Sale Order harus diisi') + if self.is_po: + raise UserError('Sudah jadi PO, tidak bisa di create ulang PO nya') + + # old_requisition = self.env['requisition'].search([('sale_order_id', '=', self.sale_order_id.id)], limit=1) + # if old_requisition: + # raise UserError('Sudah pernah jadi Requisition') + + count = 0 + for order_line in self.sale_order_id.order_line: + # get purchase price altama, if nothing, then get other cheaper, if nothing then last po + purchase_price = 0 + vendor_id = 0 + + purchase_pricelist = self.env['purchase.pricelist'].search([ + ('product_id.id', '=', order_line.product_id.id), + ('vendor_id.id', '=', 5571) + ], order='product_price asc', limit=1) + purchase_price = purchase_pricelist.product_price + vendor_id = purchase_pricelist.vendor_id.id + source = 'PriceList' + + if not purchase_price or purchase_price <= 0: + purchase_pricelist = self.env['purchase.pricelist'].search([('product_id', '=', order_line.product_id.id)], order='product_price asc', limit=1) + purchase_price = purchase_pricelist.product_price + vendor_id = purchase_pricelist.vendor_id.id + source = 'PriceList' + + if not purchase_price or purchase_price <= 0: + last_po_line = self.env['purchase.order.line'].search([('product_id', '=', order_line.product_id.id), ('order_id.state', '=', 'done')], order='id desc', limit=1) + purchase_price = last_po_line.price_unit + vendor_id = last_po_line.order_id.partner_id.id + source = 'LastPO' + + if not purchase_price or purchase_price <= 0: + purchase_price = 0 + vendor_id = 5571 + source = 'Nothing' + + self.env['requisition.line'].create([{ + 'requisition_id': self.id, + 'partner_id': vendor_id, + 'brand_id': order_line.product_id.product_tmpl_id.x_manufacture.id, + 'product_id': order_line.product_id.id, + 'qty_purchase': order_line.product_uom_qty, + 'tax_id': order_line.purchase_tax_id.id, + 'price_unit': purchase_price, + 'subtotal': purchase_price * order_line.product_uom_qty, + 'source': source + }]) + count+=1 + _logger.info('Create Requisition %s' % order_line.product_id.name) + self.notification = "Requisition Created %s lines" % count + + def create_po_from_requisition(self): + if not self.requisition_lines: + raise UserError('Tidak ada Lines, belum bisa create PO') + if self.is_po: + raise UserError('Sudah pernah di create PO') + current_time = datetime.now() + vendor_ids = self.env['requisition.line'].read_group([('requisition_id', '=', self.id), ('partner_id', '!=', False)], fields=['partner_id'], groupby=['partner_id']) + + counter_po_number = 0 + for vendor in vendor_ids: + param_header = { + 'partner_id': vendor['partner_id'][0], + 'partner_ref': self.sale_order_id.name, + 'currency_id': 12, + 'user_id': self.env.user.id, + 'company_id': 1, # indoteknik dotcom gemilang + 'picking_type_id': 28, # indoteknik bandengan receipts + 'date_order': current_time, + 'sale_order_id': self.sale_order_id.id + } + # new_po = self.env['purchase.order'].create([param_header]) + products_vendors = self.env['requisition.line'].search([ + ('requisition_id', '=', self.id), + ('partner_id', '=', vendor['partner_id'][0]), + ('qty_purchase', '>', 0) + ], order='brand_id') + count = brand_id = 0 + new_po = '' + for product in products_vendors: + if not new_po or ((count == 200 or brand_id != product.brand_id.id) and vendor['partner_id'][0] == 5571): + count = 0 + counter_po_number += 1 + new_po = self.env['purchase.order'].create([param_header]) + new_po.name = new_po.name + "/R/"+str(counter_po_number) + self.env['requisition.purchase.match'].create([{ + 'requisition_id': self.id, + 'order_id': new_po.id + }]) + self.env.cr.commit() + # else: + # new_po = self.env['purchase.order'].create([param_header]) + brand_id = product.brand_id.id + count += 10 + param_line = { + 'order_id': new_po.id, + 'sequence': count, + 'product_id': product.product_id.id, + 'product_qty': product.qty_purchase, + 'product_uom_qty': product.qty_purchase, + 'price_unit': product.last_price, + 'taxes_id': product.tax_id + } + new_line = self.env['purchase.order.line'].create([param_line]) + product.current_po_id = new_po.id + product.current_po_line_id = new_line.id + _logger.info('Create PO Line %s' % product.product_id.name) + self.notification = self.notification + ' %s' % new_po.name + self.is_po = True + +class RequisitionLine(models.Model): + _name = 'requisition.line' + _description = 'Requisition Line' + _order = 'requisition_id, id' + + requisition_id = fields.Many2one('requisition', string='Ref', required=True, ondelete='cascade', index=True, copy=False) + brand_id = fields.Many2one('x_manufactures', string='Brand') + product_id = fields.Many2one('product.product', string='Product') + partner_id = fields.Many2one('res.partner', string='Vendor') + qty_purchase = fields.Float(string='Qty Purchase') + price_unit = fields.Float(string='Price') + tax_id = fields.Many2one('account.tax', help='isi tax pembelian include atau exclude', domain="[('type_tax_use', '=', 'purchase')]") + subtotal = fields.Float(string='Subtotal') + last_price = fields.Float(string='Last Price') + last_order_id = fields.Many2one('purchase.order', string='Last Order') + last_orderline_id = fields.Many2one('purchase.order.line', string='Last Order Line') + is_po = fields.Boolean(String='Is PO') + current_po_id = fields.Many2one('purchase.order', string='Current') + current_po_line_id = fields.Many2one('purchase.order.line', string='Current Line') + source = fields.Char(string='Source', help='data harga diambil darimana') + +class RequisitionPurchaseMatch(models.Model): + _name = 'requisition.purchase.match' + _order = 'requisition_id, id' + + requisition_id = fields.Many2one('requisition', string='Ref', required=True, ondelete='cascade', index=True, copy=False) + order_id = fields.Many2one('purchase.order', string='Purchase Order') + vendor = fields.Char(string='Vendor', compute='_compute_info_po') + total = fields.Float(string='Total', compute='_compute_info_po') + + def _compute_info_po(self): + for match in self: + match.vendor = match.order_id.partner_id.name + match.total = match.order_id.amount_total diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index eaf93717..77abaaf9 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -1,4 +1,5 @@ from odoo import models, fields +from odoo.exceptions import UserError, ValidationError class GroupPartner(models.Model): _name = 'group.partner' @@ -13,3 +14,9 @@ class ResPartner(models.Model): custom_pricelist_id = fields.Many2one('product.pricelist', string='Price Matrix') group_partner_id = fields.Many2one('group.partner', string='Group Partner') + def unlink(self): + if self._name == 'res.partner': + raise UserError('Maaf anda tidak bisa delete contact') + + + diff --git a/indoteknik_custom/models/sale_monitoring.py b/indoteknik_custom/models/sale_monitoring.py index a3265a8b..e79ff9ab 100755 --- a/indoteknik_custom/models/sale_monitoring.py +++ b/indoteknik_custom/models/sale_monitoring.py @@ -20,6 +20,7 @@ class SaleMonitoring(models.Model): date_order = fields.Datetime(string="Date Order") status = fields.Char(string="Status") po_number = fields.Char(string="PO Number") + qty_reserved = fields.Integer(string="Qty Reserved") def init(self): tools.drop_view_if_exists(self.env.cr, self._table) @@ -36,14 +37,14 @@ class SaleMonitoring(models.Model): SUM(smd.qty_po_received) AS qty_po_received, SUM(smd.qty_so_delivered) AS qty_so_delivered, SUM(smd.qty_so_invoiced) AS qty_so_invoiced, + sum(smd.qty_reserved) as qty_reserved, CASE - WHEN SUM(qty_po) < SUM(qty_so) AND SUM(qty_po) <= 0 THEN 'Belum PO sama sekali' - WHEN SUM(qty_po) < SUM(qty_so) THEN 'Belum PO full' - WHEN SUM(qty_po_received) < SUM(qty_so) AND SUM(qty_po_received) <= 0 THEN 'Belum Received sama sekali' - WHEN SUM(qty_po_received) < SUM(qty_so) THEN 'Belum Received full' - WHEN SUM(qty_to_delivered) = SUM(qty_so) THEN 'SIAP KIRIM' - WHEN SUM(qty_to_delivered) < SUM(qty_so) and SUM(qty_to_delivered) > 0 THEN 'KIRIM SISANYA' - ELSE 'Belum Invoiced' + when sum(qty_so_invoiced) = sum(qty_so) then 'Invoiced' + when sum(qty_so_delivered) = sum(qty_so) then 'Delivered' + when sum(qty_reserved) >= sum(qty_so) then 'Siap kirim' + when sum(qty_po) + sum(qty_reserved) - sum(qty_po_received) < sum(qty_so) then 'Belum/Kurang PO' + when sum(qty_po_received) = 0 then 'Belum terima' + when sum(qty_po_received) < sum(qty_po) then 'Terima sebagian' END AS status, get_po_number(smd.sale_order_id) as po_number FROM sale_monitoring_detail smd diff --git a/indoteknik_custom/models/sale_monitoring_detail.py b/indoteknik_custom/models/sale_monitoring_detail.py index a578f67b..2bcda50c 100755 --- a/indoteknik_custom/models/sale_monitoring_detail.py +++ b/indoteknik_custom/models/sale_monitoring_detail.py @@ -21,6 +21,7 @@ class SaleMonitoringDetail(models.Model): qty_so_invoiced = fields.Integer(string="Qty SO Invoiced") date_order = fields.Datetime(string="Date Order") status = fields.Char(string="Status") + qty_reserved = fields.Integer(string="Qty Reserved") def init(self): tools.drop_view_if_exists(self.env.cr, self._table) @@ -29,14 +30,12 @@ class SaleMonitoringDetail(models.Model): SELECT *, CASE - WHEN qty_so = qty_so_invoiced then 'Done' - WHEN qty_po < qty_so AND qty_po <= 0 THEN 'Belum PO sama sekali' - WHEN qty_po < qty_so THEN 'Belum PO full' - WHEN qty_po_received < qty_so and qty_po_received <= 0 THEN 'Belum Received sama sekali' - WHEN qty_po_received < qty_so THEN 'Belum Received full' - WHEN qty_to_delivered = qty_so THEN 'SIAP KIRIM' - WHEN qty_to_delivered < qty_so and qty_to_delivered > 0 THEN 'KIRIM SISANYA' - ELSE 'Belum Invoiced' + when qty_so_invoiced = qty_so then 'Invoiced' + when qty_so_delivered = qty_so then 'Delivered' + when qty_reserved >= qty_so then 'Siap kirim' + when qty_po + qty_reserved - qty_po_received < qty_so then 'Belum/Kurang PO' + when qty_po_received = 0 then 'Belum terima' + when qty_po_received < qty_po then 'Terima sebagian' END AS status FROM ( @@ -52,7 +51,8 @@ class SaleMonitoringDetail(models.Model): sol.qty_invoiced AS qty_so_invoiced, so.date_order AS date_order, get_qty_po(so.id, sol.product_id) AS qty_po, - get_qty_received(so.id, sol.product_id) AS qty_po_received + get_qty_received(so.id, sol.product_id) AS qty_po_received, + get_qty_reserved(so.id, sol.product_id) as qty_reserved FROM sale_order so JOIN sale_order_line sol ON sol.order_id = so.id JOIN product_product p ON p.id = sol.product_id diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 85d7e595..cbc6a60a 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -5,6 +5,9 @@ import logging import warnings import random import string +import requests +import math +import json _logger = logging.getLogger(__name__) @@ -50,7 +53,7 @@ class SaleOrder(models.Model): ('terproses', 'Terproses'), ('sebagian', 'Sebagian Diproses'), ('menunggu', 'Menunggu Diproses'), - ]) + ], copy=False) partner_purchase_order_name = fields.Char(string='Nama PO Customer', copy=False, help="Nama purchase order customer, diisi oleh customer melalui website.", tracking=3) partner_purchase_order_description = fields.Text(string='Keterangan PO Customer', copy=False, help="Keterangan purchase order customer, diisi oleh customer melalui website.", tracking=3) partner_purchase_order_file = fields.Binary(string='File PO Customer', copy=False, help="File purchase order customer, diisi oleh customer melalui website.") @@ -74,6 +77,36 @@ class SaleOrder(models.Model): notification = fields.Char(string='Notification', help='Dapat membantu error dari approval') 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') + + def generate_payment_link_midtrans_sales_order(self): + # midtrans_url = 'https://app.sandbox.midtrans.com/snap/v1/transactions' # dev - sandbox + # midtrans_auth = 'Basic U0ItTWlkLXNlcnZlci1uLVY3ZDJjMlpCMFNWRUQyOU95Q1dWWXA6' # dev - sandbox + midtrans_url = 'https://app.midtrans.com/snap/v1/transactions' # production + midtrans_auth = 'Basic TWlkLXNlcnZlci1SbGMxZ2gzWGpSVW5scl9JblZzTV9OTnU6' # production + so_number = self.name + so_number = so_number.replace('/', '-') + so_grandtotal = math.floor(self.grand_total) + headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': midtrans_auth, + } + + json_data = { + 'transaction_details': { + 'order_id': so_number, + 'gross_amount': so_grandtotal, + }, + 'credit_card': { + 'secure': True, + }, + } + + response = requests.post(midtrans_url, headers=headers, json=json_data).json() + lookup_json = json.dumps(response, indent=4, sort_keys=True) + redirect_url = json.loads(lookup_json)['redirect_url'] + self.payment_link_midtrans = str(redirect_url) @api.model def _generate_so_access_token(self, limit=50): @@ -116,6 +149,33 @@ class SaleOrder(models.Model): sale.so_status = 'terproses' _logger.info('Calculate SO Status %s' % sale.id) + def _calculate_all_so_status(self, limit=500): + so_state = ['sale'] + sales = self.env['sale.order'].search([ + ('state', 'in', so_state), + # ('so_status', '!=', 'terproses'), + ], order='id desc', limit=limit) + for sale in sales: + sum_qty_ship = sum_qty_so = 0 + have_outstanding_pick = False + + for pick in sale.picking_ids: + if pick.state == 'draft' or pick.state == 'assigned' or pick.state == 'confirmed' or pick.state == 'waiting': + have_outstanding_pick = True + + for so_line in sale.order_line: + sum_qty_so += so_line.product_uom_qty + sum_qty_ship += so_line.qty_delivered + + if have_outstanding_pick: + if sum_qty_so > sum_qty_ship > 0: + sale.so_status = 'sebagian' + else: + sale.so_status = 'menunggu' + else: + sale.so_status = 'terproses' + _logger.info('Calculate All SO Status %s' % sale.id) + def calculate_so_status(self): so_state = ['sale'] sales = self.env['sale.order'].search([ @@ -168,7 +228,7 @@ class SaleOrder(models.Model): order.have_outstanding_invoice = False def _have_outstanding_picking(self): - picking_state = ['done', 'confirmed', 'draft', 'cancel'] + picking_state = ['done', 'confirmed', 'draft'] for order in self: if not order.picking_ids: order.have_outstanding_picking = False @@ -251,6 +311,9 @@ class SaleOrder(models.Model): for line in order.order_line: if not line.product_id or line.product_id.type == 'service': continue + # 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: raise UserError(_('Tidak bisa Confirm menggunakan Produk Sementara')) if not line.vendor_id or not line.purchase_price: @@ -266,12 +329,15 @@ class SaleOrder(models.Model): def action_cancel(self): # TODO stephan prevent cancel if have invoice, do, and po + if self._name != 'sale.order': + return super(SaleOrder, self).action_cancel() + if self.have_outstanding_invoice: raise UserError("Invoice harus di Cancel dahulu") - # elif self.have_outstanding_picking: - # raise UserError("DO harus di Cancel dahulu") - # elif self.have_outstanding_po: - # raise UserError("PO harus di Cancel dahulu") + elif self.have_outstanding_picking: + raise UserError("DO harus di Cancel dahulu") + elif self.have_outstanding_po: + raise UserError("PO harus di Cancel dahulu") self.approval_status = False return super(SaleOrder, self).action_cancel() @@ -289,6 +355,9 @@ class SaleOrder(models.Model): for line in order.order_line: if not line.product_id or line.product_id.type == 'service': continue + # 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: raise UserError(_('Tidak bisa Confirm menggunakan Produk Sementara')) if not line.vendor_id or not line.purchase_price or not line.purchase_tax_id: @@ -365,7 +434,10 @@ class SaleOrder(models.Model): def _compute_grand_total(self): for order in self: - order.grand_total = order.delivery_amt + order.amount_total + if order.shipping_cost_covered == 'customer': + order.grand_total = order.delivery_amt + order.amount_total + else: + order.grand_total = order.amount_total class SaleOrderLine(models.Model): @@ -422,15 +494,15 @@ class SaleOrderLine(models.Model): if not self.product_id or self.product_id.type == 'service': return elif self.product_id.categ_id.id == 34: # finish good / manufacturing only - print('a') - bom = self.env['mrp.bom'].search( - [('product_tmpl_id', '=', self.product_id.product_tmpl_id.id)] - , limit=1) - cost = 0 - for line in bom.bom_line_ids: - purchase_price = self.env['purchase.pricelist'].search( - [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', line.product_id.id)], limit=1) - cost += purchase_price.product_price + # bom = self.env['mrp.bom'].search( + # [('product_tmpl_id', '=', self.product_id.product_tmpl_id.id)] + # , limit=1) + # cost = 0 + # for line in bom.bom_line_ids: + # purchase_price = self.env['purchase.pricelist'].search( + # [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', line.product_id.id)], limit=1) + # cost += purchase_price.product_price + cost = self.product_id.standard_price self.purchase_price = cost else: purchase_price = self.env['purchase.pricelist'].search( diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index e63370f5..c8424121 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -59,6 +59,10 @@ class StockPicking(models.Model): ('approved', 'Approved'), ], string='Approval Return Status', readonly=True, copy=False, index=True, tracking=3, help="Approval Status untuk Return") date_doc_kirim = fields.Datetime(string='Tanggal Kirim di SJ', help="Tanggal Kirim di cetakan SJ, tidak berpengaruh ke Accounting") + note_logistic = fields.Selection([ + ('hold', 'Hold by Sales'), + ('not_paid', 'Customer belum bayar') + ], string='Note', help='jika field ini diisi maka tidak akan dihitung ke lead time') def action_create_invoice_from_mr(self): """Create the invoice associated to the PO. @@ -248,6 +252,9 @@ class StockPicking(models.Model): return def button_validate(self): + if self._name != 'stock.picking': + return super(StockPicking, self).button_validate() + if not self.picking_code: self.picking_code = self.env['ir.sequence'].next_by_code('stock.picking.code') or '0' @@ -256,6 +263,11 @@ class StockPicking(models.Model): if self.is_internal_use and not self.env.user.is_accounting: raise UserError("Harus di Approve oleh Accounting") + + if self.group_id.sale_id: + if self.group_id.sale_id.payment_link_midtrans: + if self.group_id.sale_id.payment_status != 'settlement': + raise UserError('Uang belum masuk (settlement), mohon konfirmasi ke sales atau finance') if self.is_internal_use: stock_move_lines = self.env['stock.move.line'].search([ diff --git a/indoteknik_custom/models/typesense_client.py b/indoteknik_custom/models/typesense_client.py new file mode 100644 index 00000000..fccd04e3 --- /dev/null +++ b/indoteknik_custom/models/typesense_client.py @@ -0,0 +1,150 @@ +from odoo import models +import typesense +import logging +import time + + +_logger = logging.getLogger(__name__) +_typesense = typesense.Client({ + 'nodes': [{ + 'host': 'localhost', + 'port': '9090', + 'protocol': 'http' + }], + 'api_key': 'WKWKdwakdjopwakfoij21321fkdmvaskamd' +}) + +class Typesense(models.Model): + _name = 'typesense.client' + + def _check_collection(self, name): + collections = _typesense.collections.retrieve() + for collection in collections: + if collection['name'] == name: + return True + return False + + def _init_collection(self, name): + is_exist = self._check_collection(name) + if is_exist: + return False + + schema = { + "name": name, + "fields": [ + {"name": ".*", "type": "auto" }, + {"name": ".*_facet", "type": "auto", "facet": True } + ] + } + _typesense.collections.create(schema) + return True + + def _indexing_product(self, limit=500): + start_time = time.time() + self._init_collection('products') + + query = ["&", "&", ("type", "=", "product"), ("active", "=", True), "|", ("solr_flag", "=", 0), ("solr_flag", "=", 2)] + product_templates = self.env['product.template'].search(query, limit=limit) + + counter = 0 + documents = [] + for product_template in product_templates: + counter += 1 + template_time = time.time() + document = self._map_product_document(product_template) + documents.append(document) + product_template.solr_flag = 1 + _logger.info('[SYNC_PRODUCT_TO_TYPESENSE] {}/{} {:.6f}'.format(counter, limit, time.time() - template_time)) + _logger.info('[SYNC_PRODUCT_TO_TYPESENSE] Success add to typesense product %s' % product_template.id) + + _typesense.collections['products'].documents.import_(documents, {'action': 'upsert'}) + end_time = time.time() + _logger.info("[SYNC_PRODUCT_TO_SOLR] Finish task add to solr. Time taken: {:.6f} seconds".format(end_time - start_time)) + + def _map_product_document(self, product_template): + price_excl_after_disc = price_excl = discount = tax = 0 + variants_name = variants_code = '' + flashsale_data = tier1 = tier2 = tier3 = {} + if product_template.product_variant_count > 1: + for variant in product_template.product_variant_ids: + if price_excl_after_disc == 0 or variant._get_website_price_after_disc_and_tax() < price_excl_after_disc: + price_excl = variant._get_website_price_exclude_tax() + price_excl_after_disc = variant._get_website_price_after_disc_and_tax() + discount = variant._get_website_disc(0) + tax = variant._get_website_tax() + flashsale_data = variant._get_flashsale_price() + # add price tiering for base price, discount, and price after discount (tier 1 - 3) + tier1 = variant._get_pricelist_tier1() + tier2 = variant._get_pricelist_tier2() + tier3 = variant._get_pricelist_tier3() + else: + price_excl_after_disc = price_excl_after_disc + price_excl = price_excl + discount = discount + tax = tax + flashsale_data = flashsale_data + tier1 = tier1 + tier2 = tier2 + tier3 = tier3 + variants_name += variant.display_name or ''+', ' + variants_code += variant.default_code or ''+', ' + else: + variants_name = product_template.display_name + price_excl = product_template.product_variant_id._get_website_price_exclude_tax() + discount = product_template.product_variant_id._get_website_disc(0) + price_excl_after_disc = product_template.product_variant_id._get_website_price_after_disc_and_tax() + tax = product_template.product_variant_id._get_website_tax() + flashsale_data = product_template.product_variant_id._get_flashsale_price() + tier1 = product_template.product_variant_id._get_pricelist_tier1() + tier2 = product_template.product_variant_id._get_pricelist_tier2() + tier3 = product_template.product_variant_id._get_pricelist_tier3() + + category_id = '' + category_name = '' + for category in product_template.public_categ_ids: + category_id = category.id + category_name = category.name + + document = { + 'id': str(product_template.id), + 'display_name': product_template.display_name, + 'name': product_template.name, + 'default_code': product_template.default_code or '', + 'product_rating': product_template.virtual_rating, + 'product_id': product_template.id, + 'image': self.env['ir.attachment'].api_image('product.template', 'image_512', product_template.id), + 'price': price_excl, + 'discount': discount, + 'price_discount': price_excl_after_disc, + 'tax': tax, + 'variant_total': product_template.product_variant_count, + 'stock_total': product_template.qty_stock_vendor, + 'weight': product_template.weight, + 'manufacture_id': product_template.x_manufacture.id or 0, + 'manufacture_name': product_template.x_manufacture.x_name or '', + 'manufacture_name': product_template.x_manufacture.x_name or '', + 'image_promotion_1': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_1', product_template.x_manufacture.id), + 'image_promotion_2': self.env['ir.attachment'].api_image('x_manufactures', 'image_promotion_2', product_template.x_manufacture.id), + 'category_id': category_id or 0, + 'category_name': category_name or '', + 'category_name': category_name or '', + 'variants_name_t': variants_name, + 'variants_code_t': variants_code, + 'search_rank': product_template.search_rank, + 'search_rank_weekly': product_template.search_rank_weekly, + 'flashsale_id': flashsale_data['flashsale_id'] or 0, + 'flashsale_name': flashsale_data['flashsale_name'] or '', + 'flashsale_base_price': flashsale_data['flashsale_base_price'] or 0, + 'flashsale_discount': flashsale_data['flashsale_discount'] or 0, + 'flashsale_price': flashsale_data['flashsale_price'] or 0, + 'discount_tier1': tier1['discount_tier1'] or 0, + 'price_tier1': tier1['price_tier1'] or 0, + 'discount_tier2': tier2['discount_tier2'] or 0, + 'price_tier2': tier2['price_tier2'] or 0, + 'discount_tier3': tier3['discount_tier3'] or 0, + 'price_tier3': tier3['price_tier3'] or 0 + } + + return document + + diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index f782046d..3d23529f 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -49,7 +49,13 @@ access_group_partner,access.group.partner,model_group_partner,,1,1,1,1 access_procurement_monitoring_detail,access.procurement.monitoring.detail,model_procurement_monitoring_detail,,1,1,1,1 access_rajaongkir_kurir,access.rajaongkir.kurir,model_rajaongkir_kurir,,1,1,1,1 access_brand_vendor,access.brand.vendor,model_brand_vendor,,1,1,1,1 +<<<<<<< HEAD access_promotion_program,access.promotion.program,model_promotion_program,,1,1,1,1 access_promotion_program_line,access.promotion.program.line,model_promotion_program_line,,1,1,1,1 access_promotion_program_free_item,access.promotion.program.free_item,model_promotion_program_free_item,,1,1,1,1 -access_promotion_program_keyword,access.promotion.program.keyword,model_promotion_program_keyword,,1,1,1,1
\ No newline at end of file +access_promotion_program_keyword,access.promotion.program.keyword,model_promotion_program_keyword,,1,1,1,1 +======= +access_requisition,access.requisition,model_requisition,,1,1,1,1 +access_requisition_line,access.requisition.line,model_requisition_line,,1,1,1,1 +access_requisition_purchase_match,access.requisition.purchase.match,model_requisition_purchase_match,,1,1,1,1 +>>>>>>> 24649f8e939484759ef34e5e68f251d951f63c02 diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml index 6a6f474d..9af85408 100644 --- a/indoteknik_custom/views/ir_sequence.xml +++ b/indoteknik_custom/views/ir_sequence.xml @@ -30,5 +30,15 @@ <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> + <field name="active">TRUE</field> + <field name="prefix">RPO/%(year)s/</field> + <field name="padding">5</field> + <field name="number_next">1</field> + <field name="number_increment">1</field> + </record> </data> </odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/landedcost.xml b/indoteknik_custom/views/landedcost.xml new file mode 100644 index 00000000..4736941a --- /dev/null +++ b/indoteknik_custom/views/landedcost.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <data> + <record id="landed_cost_form_inherit" model="ir.ui.view"> + <field name="name">Landed Cost</field> + <field name="model">stock.landed.cost</field> + <field name="inherit_id" ref="stock_landed_costs.view_stock_landed_cost_form"/> + <field name="arch" type="xml"> + <field name="vendor_bill_id" position="replace"> + <field name="vendor_bill_id" required="1"/> + </field> + </field> + </record> + </data> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/requisition.xml b/indoteknik_custom/views/requisition.xml new file mode 100644 index 00000000..6e61ce1e --- /dev/null +++ b/indoteknik_custom/views/requisition.xml @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <record id="requisition_tree" model="ir.ui.view"> + <field name="name">requisition.tree</field> + <field name="model">requisition</field> + <field name="arch" type="xml"> + <tree> + <field name="date_doc"/> + <field name="number"/> + <field name="description"/> + <field name="notification" readonly="1"/> + <field name="is_po" readonly="1"/> + </tree> + </field> + </record> + + <record id="requisition_line_tree" model="ir.ui.view"> + <field name="name">requisition.line.tree</field> + <field name="model">requisition.line</field> + <field name="arch" type="xml"> + <tree> + <field name="brand_id"/> + <field name="product_id"/> + <field name="partner_id"/> + <field name="qty_purchase"/> + <field name="price_unit"/> + <field name="tax_id"/> + <field name="subtotal"/> + <field name="source"/> + </tree> + </field> + </record> + + <record id="requisition_purchase_match_tree" model="ir.ui.view"> + <field name="name">requisition.purchase.match.tree</field> + <field name="model">requisition.purchase.match</field> + <field name="arch" type="xml"> + <tree> + <field name="order_id" readonly="1"/> + <field name="vendor" readonly="1"/> + <field name="total" readonly="1"/> + </tree> + </field> + </record> + + <record id="requisition_form" model="ir.ui.view"> + <field name="name">requisition.form</field> + <field name="model">requisition</field> + <field name="arch" type="xml"> + <form> + <sheet string="Requisition"> + <div class="oe_button_box" name="button_box"/> + <group> + <group> + <field name="number"/> + <field name="date_doc"/> + <field name="sale_order_id"/> + <field name="description"/> + <field name="notification" readonly="1"/> + </group> + <group> + <div> + <button name="create_requisition_from_sales" + string="Create Line" + type="object" + class="mr-2 oe_highlight" + /> + <button name="create_po_from_requisition" + string="Create PO" + type="object" + class="mr-2 oe_highlight" + /> + </div> + </group> + </group> + <notebook> + <page string="Lines"> + <field name="requisition_lines"/> + </page> + <page string="Matches"> + <field name="requisition_match"/> + </page> + </notebook> + </sheet> + </form> + </field> + </record> + + <record id="requisition_action" model="ir.actions.act_window"> + <field name="name">Requisition</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">requisition</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem id="menu_requisition" + name="Requisition" + action="requisition_action" + parent="menu_monitoring_in_purchase" + sequence="300"/> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/sale_monitoring.xml b/indoteknik_custom/views/sale_monitoring.xml index b3b186e9..956e4a24 100755 --- a/indoteknik_custom/views/sale_monitoring.xml +++ b/indoteknik_custom/views/sale_monitoring.xml @@ -13,16 +13,17 @@ <field name="partner_id"/> <field name="user_id"/> <field name="qty_so"/> + <field name="qty_reserved"/> <field name="qty_po"/> <field name="qty_po_received"/> <field name="qty_so_delivered"/> <field name="qty_so_invoiced"/> <field name="status" widget="badge" - decoration-danger="status == 'Belum PO sama sekali' or status == 'Belum PO full'" - decoration-warning="status == 'Belum Received sama sekali' or status == 'Belum Received full'" - decoration-success="status == 'SIAP KIRIM' or status == 'KIRIM SISANYA'" - decoration-info="status == 'Belum Invoiced'" + decoration-danger="status == 'Belum/Kurang PO'" + decoration-warning="status == 'Belum terima' or status == 'Terima sebagian'" + decoration-success="status == 'Siap kirim'" + decoration-info="status == 'Delivered' or status == 'Invoiced'" /> </tree> </field> @@ -41,15 +42,16 @@ <field name="user_id"/> <field name="status" widget="badge" - decoration-danger="status == 'Belum PO sama sekali' or status == 'Belum PO full'" - decoration-warning="status == 'Belum Received sama sekali' or status == 'Belum Received full'" - decoration-success="status == 'SIAP KIRIM' or status == 'KIRIM SISANYA'" - decoration-info="status == 'Belum Invoiced'" + decoration-danger="status == 'Belum/Kurang PO'" + decoration-warning="status == 'Belum terima' or status == 'Terima sebagian'" + decoration-success="status == 'Siap kirim'" + decoration-info="status == 'Delivered' or status == 'Invoiced'" /> <field name="po_number"/> </group> <group> <field name="qty_so"/> + <field name="qty_reserved"/> <field name="qty_po"/> <field name="qty_po_received"/> <field name="qty_so_delivered"/> diff --git a/indoteknik_custom/views/sale_monitoring_detail.xml b/indoteknik_custom/views/sale_monitoring_detail.xml index b9602abd..736920b3 100755 --- a/indoteknik_custom/views/sale_monitoring_detail.xml +++ b/indoteknik_custom/views/sale_monitoring_detail.xml @@ -11,16 +11,17 @@ <field name="user_id"/> <field name="product_id"/> <field name="qty_so"/> + <field name="qty_reserved"/> <field name="qty_po"/> <field name="qty_po_received"/> <field name="qty_so_delivered"/> <field name="qty_so_invoiced"/> <field name="status" widget="badge" - decoration-danger="status == 'Belum PO sama sekali' or status == 'Belum PO full'" - decoration-warning="status == 'Belum Received sama sekali' or status == 'Belum Received full'" - decoration-success="status == 'SIAP KIRIM' or status == 'KIRIM SISANYA'" - decoration-info="status == 'Belum Invoiced' or status == 'Done'" + decoration-danger="status == 'Belum/Kurang PO'" + decoration-warning="status == 'Belum terima' or status == 'Terima sebagian'" + decoration-success="status == 'Siap kirim'" + decoration-info="status == 'Delivered' or status == 'Invoiced'" /> </tree> </field> @@ -40,14 +41,15 @@ <field name="product_id"/> <field name="status" widget="badge" - decoration-danger="status == 'Belum PO sama sekali' or status == 'Belum PO full'" - decoration-warning="status == 'Belum Received sama sekali' or status == 'Belum Received full'" - decoration-success="status == 'SIAP KIRIM' or status == 'KIRIM SISANYA'" - decoration-info="status == 'Belum Invoiced'" + decoration-danger="status == 'Belum/Kurang PO'" + decoration-warning="status == 'Belum terima' or status == 'Terima sebagian'" + decoration-success="status == 'Siap kirim'" + decoration-info="status == 'Delivered' or status == 'Invoiced'" /> </group> <group> <field name="qty_so"/> + <field name="qty_reserved"/> <field name="qty_po"/> <field name="qty_po_received"/> <field name="qty_so_delivered"/> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index c66201a9..ea13c954 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -19,8 +19,8 @@ type="action" attrs="{'invisible': [('approval_status', '!=', 'approved')]}"/> </button> <field name="payment_term_id" position="after"> - <field name="shipping_cost_covered"/> - <field name="shipping_paid_by"/> + <field name="shipping_cost_covered" required="1"/> + <field name="shipping_paid_by" required="1"/> <field name="delivery_amt"/> <field name="fee_third_party"/> <field name="total_percent_margin"/> @@ -82,6 +82,11 @@ <field name="partner_purchase_order_file" readonly="True"/> </group> <group> + <button name="generate_payment_link_midtrans_sales_order" + string="Create Payment Link" + type="object" + /> + <field name="payment_link_midtrans" readonly="True" widget="url"/> <field name="gross_amount" readonly="True"/> <field name="payment_type" readonly="True"/> <field name="payment_status" readonly="True"/> diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index e4e9f722..4bbdc7b8 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -7,10 +7,11 @@ <field name="inherit_id" ref="stock.vpicktree"/> <field name="arch" type="xml"> <field name="json_popover" position="after"> - <field name="date_done"/> - <field name="date_doc_kirim"/> - <field name="driver_departure_date"/> - <field name="driver_arrival_date"/> + <field name="date_done" optional="hide"/> + <field name="date_doc_kirim" optional="hide"/> + <field name="driver_departure_date" optional="hide"/> + <field name="driver_arrival_date" optional="hide"/> + <field name="note_logistic" optional="hide"/> </field> </field> </record> @@ -80,6 +81,7 @@ <page string="Delivery" name="delivery_order"> <group> <group> + <field name="note_logistic"/> <field name="driver_departure_date"/> <field name="driver_arrival_date"/> <field name="delivery_tracking_no"/> |
