diff options
38 files changed, 693 insertions, 72 deletions
diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py index f472a9b0..2a24b205 100644 --- a/indoteknik_api/controllers/api_v1/cart.py +++ b/indoteknik_api/controllers/api_v1/cart.py @@ -16,10 +16,28 @@ class Cart(controller.Controller): offset = int(kw.get('offset', 0)) query = [('user_id', '=', user_id)] carts = user_cart.search(query, limit=limit, offset=offset, order='create_date desc') - carts.write({'source': 'add_to_cart'}) + # carts.write({'source': 'add_to_cart'}) + products = [] + products_inactive = [] + for cart in carts: + if cart.product_id: + price = cart.product_id._v2_get_website_price_include_tax() + if cart.product_id.active and price > 0: + product = cart.with_context(price_for="web").get_products() + for product_active in product: + products.append(product_active) + else: + product_inactives = cart.with_context(price_for="web").get_products() + for inactives in product_inactives: + products_inactive.append(inactives) + else: + program = cart.with_context(price_for="web").get_products() + for programs in program: + products.append(programs) data = { 'product_total': user_cart.search_count(query), - 'products': carts.with_context(price_for="web").get_products() + 'products': products, + 'products_inactive': products_inactive } return self.response(data) diff --git a/indoteknik_api/controllers/api_v1/category_management.py b/indoteknik_api/controllers/api_v1/category_management.py index 836f4493..c0ecc6b9 100644 --- a/indoteknik_api/controllers/api_v1/category_management.py +++ b/indoteknik_api/controllers/api_v1/category_management.py @@ -2,6 +2,7 @@ from odoo import http from odoo.http import request from .. import controller + class CategoryManagement(controller.Controller): prefix = '/api/v1/' @@ -42,5 +43,3 @@ class CategoryManagement(controller.Controller): 'categories': category_id2_data, }) return self.response(data, headers=[('Cache-Control', 'max-age=3600, public')]) - - diff --git a/indoteknik_api/controllers/api_v1/partner.py b/indoteknik_api/controllers/api_v1/partner.py index 3cc6b193..663f4d7d 100644 --- a/indoteknik_api/controllers/api_v1/partner.py +++ b/indoteknik_api/controllers/api_v1/partner.py @@ -180,4 +180,32 @@ class Partner(controller.Controller): }) return self.response(data) + + @http.route(prefix + 'check/<partner_id>/tempo', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_check_tempo_partner(self, **kw): + partner_id = int(kw.get('partner_id')) + + partner = request.env['res.partner'].search([('id', '=', partner_id)], limit=1) + if not partner: + return self.response(code=404, description='Partner not found') + + partner = partner.parent_id or partner + + if any(line.days == 0 for line in partner.property_payment_term_id.line_ids): + return self.response(code=402, description='Partner not tempo') + + result_tempo = sum(m.amount_total_signed for m in request.env['account.move'].search([('partner_id', '=', partner.id), ('payment_state', '=', 'not_paid'), ('state', '=', 'posted')])) + + remaining_limit = partner.blocking_stage - result_tempo if partner.active_limit else None + + data = { + 'name': partner.name, + 'amount_due': result_tempo, + 'remaining_limit': remaining_limit + } + + return self.response(data) + + diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 7edd71f6..e7664c79 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -342,11 +342,21 @@ class SaleOrder(controller.Controller): @http.route(prefix + 'user/<user_id>/sale_order/checkout', auth='public', method=['GET', 'OPTIONS'], csrf=False) @controller.Controller.must_authorized(private=True, private_key='user_id') def get_user_checkout_so(self, user_id, **kw): - cart = request.env['website.user.cart'] + m_voucher = request.env['voucher'] + m_cart = request.env['website.user.cart'] + voucher_code = kw.get('voucher') + voucher_shipping_code = kw.get('voucher_shipping') source = kw.get('source') - voucher = request.env['voucher'].search([('code', '=', voucher_code)], limit=1) - result = cart.with_context(price_for="web").get_user_checkout(user_id, voucher, source) + + voucher = m_voucher.search([('code', '=', voucher_code), ('apply_type', 'in', ['all', 'brand'])], limit=1) + voucher_shipping = m_voucher.search([('code', '=', voucher_shipping_code), ('apply_type', '=', 'shipping')], limit=1) + result = m_cart.with_context(price_for="web").get_user_checkout( + user_id, + voucher=voucher, + voucher_shipping=voucher_shipping, + source=source + ) return self.response(result) @http.route(PREFIX_PARTNER + 'sale_order/checkout', auth='public', method=['POST', 'OPTIONS'], csrf=False) @@ -400,7 +410,7 @@ class SaleOrder(controller.Controller): 'real_invoice_id': params['value']['partner_invoice_id'], 'partner_purchase_order_name': params['value']['po_number'], 'partner_purchase_order_file': params['value']['po_file'], - 'delivery_amt': params['value']['delivery_amount'], + 'delivery_amt': params['value']['delivery_amount'] * 1.10, 'estimated_arrival_days': params['value']['estimated_arrival_days'], 'shipping_cost_covered': 'customer', 'shipping_paid_by': 'customer', @@ -455,11 +465,16 @@ class SaleOrder(controller.Controller): sale_order.apply_promotion_program() voucher_code = params['value']['voucher'] - voucher = request.env['voucher'].search([('code', '=', voucher_code)]) + voucher = request.env['voucher'].search([('code', '=', voucher_code),('apply_type', 'in', ['all', 'brand'])], limit=1) + voucher_shipping = request.env['voucher'].search([('code', '=', voucher_code),('apply_type', 'in', ['shipping'])], limit=1) if voucher and len(promotions) == 0: sale_order.voucher_id = voucher.id sale_order.apply_voucher() + if voucher_shipping and len(promotions) == 0: + sale_order.voucher_shipping_id = voucher_shipping.id + sale_order.apply_voucher_shipping() + cart_ids = [x['cart_id'] for x in carts] if sale_order._requires_approval_margin_leader(): #jika ada error tambahkan kondisi if params['value']['type'] == 'sale_order': sale_order.approval_status = 'pengajuan2' @@ -621,4 +636,61 @@ class SaleOrder(controller.Controller): } return self.response(data) -
\ No newline at end of file + + @http.route(prefix + 'tracking_order', auth='public', method=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def tracking_get_sale_order_detail(self, **kw): + # Extract 'so' and 'email' parameters from query parameters + so = kw.get('so') + email_user = kw.get('email') + + if not email_user or not so: + return self.response({ + 'code': 400, + 'so': so, + 'email': email_user, + 'description': "Email and Sale Order number are required." + }) + + # Search for the sale order by the name (so) + sale_order = request.env['sale.order'].search([('name', '=', so)], limit=1) + if not sale_order: + return self.response({ + 'code': 404, + 'so': so, + 'email': email_user, + 'description': "Sale Order not found." + }) + + # Get the partner associated with the sale order + partner = sale_order.partner_id + company_id = partner.company_id.id + + # Search for all partners within the same company + partners_in_company = request.env['res.partner'].search([('company_id', '=', company_id)]) + + # Check if the email matches any partner's email in the same company + email_match = partners_in_company.filtered(lambda p: p.email == email_user) + if not email_match: + return self.response({ + 'code': 403, + 'so': so, + 'email': email_user, + 'description': "Email does not match any partner in the same company as the Sale Order." + }) + + # Check for partner child ids if needed + partner_child_ids = self.get_partner_child_ids(partner.id) + if sale_order.partner_id.id not in partner_child_ids: + return self.response({ + 'code': 403, + 'so': so, + 'email': email_user, + 'description': "Unauthorized access to Sale Order details." + }) + + # Prepare the response data + data = request.env['sale.order'].api_v1_single_response(sale_order, context='with_detail') + + return self.response(data) + diff --git a/indoteknik_api/controllers/api_v1/stock_picking.py b/indoteknik_api/controllers/api_v1/stock_picking.py index 5e919b31..8b941c16 100644 --- a/indoteknik_api/controllers/api_v1/stock_picking.py +++ b/indoteknik_api/controllers/api_v1/stock_picking.py @@ -99,3 +99,15 @@ class StockPicking(controller.Controller): return self.response(None) return self.response(picking.get_tracking_detail()) + + @http.route(prefix + 'stock-picking/<id>/tracking', auth='public', method=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_partner_stock_picking_detail_tracking_iman(self, **kw): + id = int(kw.get('id', 0)) + picking_model = request.env['stock.picking'] + + picking = picking_model.browse(id) + if not picking: + return self.response(None) + + return self.response(picking.get_tracking_detail())
\ No newline at end of file diff --git a/indoteknik_api/controllers/api_v1/voucher.py b/indoteknik_api/controllers/api_v1/voucher.py index cd5dff20..910488d1 100644 --- a/indoteknik_api/controllers/api_v1/voucher.py +++ b/indoteknik_api/controllers/api_v1/voucher.py @@ -28,7 +28,7 @@ class Voucher(controller.Controller): domain = [] if code: visibility.append('private') - domain += [('code', '=', code)] + domain += [('code', 'ilike', code)] user_pricelist = request.env.context.get('user_pricelist') if user_pricelist: domain += [('excl_pricelist_ids', 'not in', [user_pricelist.id])] diff --git a/indoteknik_api/models/product_product.py b/indoteknik_api/models/product_product.py index 3ecad627..386ddb6a 100644 --- a/indoteknik_api/models/product_product.py +++ b/indoteknik_api/models/product_product.py @@ -234,19 +234,17 @@ class ProductProduct(models.Model): ('pricelist_id', '=', int(product_pricelist_tier)), ('product_id', '=', self.id) ], limit=1) - if pricelist_item: - # base_price = self._get_website_price_exclude_tax() - base_price_incl = self._get_website_price_include_tax() - if tier_number in ['1_v2', '2_v2', '3_v2', '4_v2', '5_v2']: - base_price_incl = self._v2_get_website_price_include_tax() - + base_price_incl = self._get_website_price_include_tax() + if tier_number in ['1_v2', '2_v2', '3_v2', '4_v2', '5_v2']: + base_price_incl = self._v2_get_website_price_include_tax() + if pricelist_item and base_price_incl: discount = pricelist_item.price_discount price = base_price_incl - (base_price_incl * discount / 100) price = price / default_divide_tax price = math.floor(price) data = { - f'discount_tier{tier_number}': discount or 0, - f'price_tier{tier_number}': price or 0 + f'discount_tier{tier_number}': discount if base_price_incl else 0, + f'price_tier{tier_number}': price if base_price_incl else 0, } return data diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index e9ce587c..ad7b1d09 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -39,6 +39,7 @@ from . import website_brand_homepage from . import website_categories_homepage from . import website_categories_lob from . import website_categories_management +from . import website_categories_management_line from . import website_content from . import website_page_content from . import website_user_cart diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index a7010bbe..725b3c2d 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -174,7 +174,7 @@ class AccountMove(models.Model): def _compute_mark_upload_efaktur(self): for move in self: - if move.date_efaktur_exported or move.is_efaktur_exported or move.efaktur_document: + if move.efaktur_document: move.mark_upload_efaktur = 'sudah_upload' else: move.mark_upload_efaktur = 'belum_upload' diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index 3561fc0f..548115e6 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -220,6 +220,7 @@ class AutomaticPurchase(models.Model): # i start from zero (0) for i in range(page): new_po = self.env['purchase.order'].create([param_header]) + new_po.payment_term_id = new_po.partner_id.property_supplier_payment_term_id new_po.name = new_po.name + name + str(i + 1) self.env['automatic.purchase.match'].create([{ @@ -261,7 +262,7 @@ class AutomaticPurchase(models.Model): new_po_line = self.env['purchase.order.line'].create([param_line]) line.current_po_id = new_po.id line.current_po_line_id = new_po_line.id - self.update_purchase_price_so_line(line) + # self.update_purchase_price_so_line(line) self.create_purchase_order_sales_match(new_po) @@ -292,6 +293,9 @@ class AutomaticPurchase(models.Model): sale_ids_set.add(sale_id_with_salesperson) sale_ids_name.add(sale_order.sale_id.name) + margin_item = sale_order.sale_line_id.item_margin / sale_order.qty_so if sale_order.qty_so else 0 + margin_item = margin_item * sale_order.qty_po + matches_so_line = { 'purchase_order_id': purchase_order.id, 'sale_id': sale_order.sale_id.id, @@ -304,7 +308,8 @@ class AutomaticPurchase(models.Model): 'product_id': sale_order.product_id.id, 'qty_so': sale_order.qty_so, 'qty_po': sale_order.qty_po, - 'margin_so': sale_order.sale_line_id.item_percent_margin + 'margin_so': sale_order.sale_line_id.item_percent_margin, + 'margin_item': margin_item } po_matches_so_line = self.env['purchase.order.sales.match'].create([matches_so_line]) diff --git a/indoteknik_custom/models/bill_receipt.py b/indoteknik_custom/models/bill_receipt.py index 76449c1f..7d38d5ad 100644 --- a/indoteknik_custom/models/bill_receipt.py +++ b/indoteknik_custom/models/bill_receipt.py @@ -22,8 +22,16 @@ class BillReceipt(models.Model): resi_tukar_faktur = fields.Char(string='Resi Faktur') date_terima_tukar_faktur = fields.Date(string='Terima Faktur') shipper_faktur_id = fields.Many2one('delivery.carrier', string='Shipper Faktur') - is_validated = fields.Boolean(string='Validated') + is_validated = fields.Boolean(string='Validated') notification = fields.Char(string='Notification') + grand_total = fields.Float(string='Grand Total', compute="_compute_grand_total") + + def _compute_grand_total(self): + for record in self: + grand_total = 0 + for line in record.bill_line: + grand_total += line.total_amt + record.grand_total = grand_total def copy_date_faktur(self): if not self.is_validated: diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py index c5809005..48f1c7f6 100644 --- a/indoteknik_custom/models/commision.py +++ b/indoteknik_custom/models/commision.py @@ -261,6 +261,7 @@ class CustomerCommision(models.Model): ('move_id.invoice_date', '>=', self.date_from), ('move_id.invoice_date', '<=', self.date_to), ('product_id.x_manufacture', 'in', brand), + ('exclude_from_invoice_tab', '=', False), ] invoice_lines = self.env['account.move.line'].search(where, order='id') for invoice_line in invoice_lines: diff --git a/indoteknik_custom/models/dunning_run.py b/indoteknik_custom/models/dunning_run.py index d75d7c51..c167aab7 100644 --- a/indoteknik_custom/models/dunning_run.py +++ b/indoteknik_custom/models/dunning_run.py @@ -27,6 +27,17 @@ class DunningRun(models.Model): shipper_faktur_id = fields.Many2one('delivery.carrier', string='Shipper Faktur') is_validated = fields.Boolean(string='Validated') notification = fields.Char(string='Notification') + is_paid = fields.Boolean(string='Paid') + description = fields.Char(string='Description') + comment = fields.Char(string='Comment') + grand_total = fields.Float(string='Grand Total', compute="_compute_grand_total") + + def _compute_grand_total(self): + for record in self: + grand_total = 0 + for line in record.dunning_line: + grand_total += line.total_amt + record.grand_total = grand_total def copy_date_faktur(self): if not self.is_validated: diff --git a/indoteknik_custom/models/product_pricelist.py b/indoteknik_custom/models/product_pricelist.py index 2b17cf6e..c299ff2f 100644 --- a/indoteknik_custom/models/product_pricelist.py +++ b/indoteknik_custom/models/product_pricelist.py @@ -1,5 +1,5 @@ from odoo import models, fields -from datetime import datetime +from datetime import datetime, timedelta class ProductPricelist(models.Model): @@ -18,6 +18,18 @@ class ProductPricelist(models.Model): banner_top = fields.Binary(string='Banner Top') flashsale_tag = fields.Char(string='Flash Sale Tag') + def _check_end_date_and_update_solr(self): + today = datetime.utcnow().date() + one_day_ago = today - timedelta(days=1) + + pricelists = self.search([ + ('is_flash_sale', '=', True) + ]) + + for pricelist in pricelists: + if fields.Date.to_date(pricelist.end_date) == one_day_ago: + pricelist._constrains_related_solr_field() + def _remaining_time_in_second(self): if not self.end_date: return 0 diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index d51f903f..031d1b5b 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -61,6 +61,12 @@ class ProductTemplate(models.Model): tkdn = fields.Boolean(string='TKDN') short_spesification = fields.Char(string='Short Spesification') + @api.constrains('name', 'internal_reference', 'x_manufacture') + def required_public_categ_ids(self): + for rec in self: + if not rec.public_categ_ids: + raise UserError('Field Categories harus diisi') + def _get_qty_sold(self): for rec in self: rec.qty_sold = sum(x.qty_sold for x in rec.product_variant_ids) @@ -332,9 +338,9 @@ class ProductTemplate(models.Model): return values def write(self, vals): - for rec in self: - if rec.id == 224484: - raise UserError('Tidak dapat mengubah produk sementara') + # for rec in self: + # if rec.id == 224484: + # raise UserError('Tidak dapat mengubah produk sementara') return super(ProductTemplate, self).write(vals) @@ -367,6 +373,12 @@ class ProductProduct(models.Model): qty_sold = fields.Float(string='Sold Quantity', compute='_get_qty_sold') short_spesification = fields.Char(string='Short Spesification') + @api.constrains('name', 'internal_reference', 'x_manufacture') + def required_public_categ_ids(self): + for rec in self: + if not rec.public_categ_ids: + raise UserError('Field Categories harus diisi') + @api.constrains('active') def archive_product(self): for product in self: @@ -376,8 +388,16 @@ class ProductProduct(models.Model): if product_template.active and product.active: if not product.active and len(variants) == 1: product_template.with_context(skip_active_constraint=True).active = False + product_template.unpublished = True elif not product.active and len(variants) > 1: - continue + all_inactive = all(not variant.active for variant in variants) + if all_inactive: + product_template.with_context(skip_active_constraint=True).active = False + product_template.unpublished = True + else: + continue + if any(variant.active for variant in variants): + product_template.unpublished = False def update_internal_reference_variants(self, limit=100): variants = self.env['product.product'].search([ diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 3a11ab1e..8a47482a 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -31,6 +31,7 @@ class PurchaseOrder(models.Model): ('approved', 'Approved'), ], string='Approval Status', readonly=True, copy=False, index=True, tracking=3) delivery_amount = fields.Float('Delivery Amount', compute='compute_delivery_amount') + delivery_amt = fields.Float('Delivery Amt') total_margin = fields.Float( 'Margin', compute='compute_total_margin', help="Total Margin in Sales Order Header") @@ -66,6 +67,72 @@ class PurchaseOrder(models.Model): ('printed', 'Printed') ], string='Printed?', copy=False, tracking=True) date_done_picking = fields.Datetime(string='Date Done Picking', compute='get_date_done') + bills_dp_id = fields.Many2one('account.move', string='Bills DP') + grand_total = fields.Monetary(string='Grand Total', help='Amount total + amount delivery', compute='_compute_grand_total') + total_margin_match = fields.Float(string='Total Margin Match', compute='_compute_total_margin_match') + + def _compute_total_margin_match(self): + for purchase in self: + match = self.env['purchase.order.sales.match'] + result = match.read_group( + [('purchase_order_id', '=', purchase.id)], + ['margin_item'], + [] + ) + purchase.total_margin_match = result[0].get('margin_item', 0.0) + + def _compute_grand_total(self): + for order in self: + if order.delivery_amt: + order.grand_total = order.delivery_amt + order.amount_total + else: + order.grand_total = order.amount_total + + def create_bill_dp(self): + if not self.env.user.is_accounting: + raise UserError('Hanya Accounting yang bisa bikin bill dp') + + current_date = datetime.utcnow() + data_bills = { + 'partner_id': self.partner_id.id, + 'partner_shipping_id': self.partner_id.id, + 'ref': self.name, + 'invoice_date': current_date, + 'date': current_date, + 'move_type': 'in_invoice' + + } + + bills = self.env['account.move'].create([data_bills]) + + product_dp = self.env['product.product'].browse(229625) + + data_line_bills = { + 'move_id': bills.id, + 'product_id': product_dp.id, #product down payment + 'account_id': 401, #Uang Muka persediaan barang dagang + 'quantity': 1, + 'product_uom_id': 1, + 'tax_ids': [line[0].taxes_id.id for line in self.order_line], + } + + + bills_line = self.env['account.move.line'].create([data_line_bills]) + + self.bills_dp_id = bills.id + + move_line = bills.line_ids + move_line.name = '[IT.121456] Down Payment' + move_line.partner_id = self.partner_id.id + + return { + 'name': _('Account Move'), + 'view_mode': 'tree,form', + 'res_model': 'account.move', + 'target': 'current', + 'type': 'ir.actions.act_window', + 'domain': [('id', '=', bills.id)] + } def get_date_done(self): picking = self.env['stock.picking'].search([ @@ -435,7 +502,7 @@ class PurchaseOrder(models.Model): res = super(PurchaseOrder, self).button_confirm() current_time = datetime.now() self.check_ppn_mix() - self.check_data_vendor() + # self.check_data_vendor() 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") @@ -624,6 +691,8 @@ class PurchaseOrder(models.Model): purchase_price = line.price_subtotal if line.order_id.delivery_amount > 0: purchase_price += line.delivery_amt_line + if line.order_id.delivery_amt > 0: + purchase_price += line.order_id.delivery_amt real_item_margin = sales_price - purchase_price sum_margin += real_item_margin @@ -666,6 +735,8 @@ class PurchaseOrder(models.Model): purchase_price = po_line.price_subtotal / po_line.product_qty * line.qty_po if line.purchase_order_id.delivery_amount > 0: purchase_price += (po_line.delivery_amt_line / po_line.product_qty) * line.qty_po + if line.purchase_order_id.delivery_amt > 0: + purchase_price += line.purchase_order_id.delivery_amt real_item_margin = sales_price - purchase_price sum_margin += real_item_margin diff --git a/indoteknik_custom/models/purchase_order_sales_match.py b/indoteknik_custom/models/purchase_order_sales_match.py index 78581409..d1d929d3 100644 --- a/indoteknik_custom/models/purchase_order_sales_match.py +++ b/indoteknik_custom/models/purchase_order_sales_match.py @@ -20,7 +20,17 @@ class PurchaseOrderSalesMatch(models.Model): product_id = fields.Many2one('product.product', string='Product') qty_so = fields.Float(string='Qty SO') qty_po = fields.Float(string='Qty PO') - margin_so = fields.Float(string='Margin SO') + margin_so = fields.Float(string='Margin SO') + margin_item = fields.Float(string='Margin') + delivery_amt = fields.Float(string='Delivery Amount', compute='_compute_delivery_amt') + margin_deduct = fields.Float(string='After Deduct', compute='_compute_delivery_amt') + + def _compute_delivery_amt(self): + for line in self: + percent_margin = line.margin_item / line.purchase_order_id.total_margin_match \ + if line.purchase_order_id.total_margin_match else 0 + line.delivery_amt = line.purchase_order_id.delivery_amt * percent_margin + line.margin_deduct = line.margin_item - line.delivery_amt @api.onchange('sale_id') def onchange_sale_id(self): diff --git a/indoteknik_custom/models/res_users.py b/indoteknik_custom/models/res_users.py index cedf19bd..d8eb348a 100755 --- a/indoteknik_custom/models/res_users.py +++ b/indoteknik_custom/models/res_users.py @@ -11,6 +11,7 @@ class ResUsers(models.Model): activation_token = fields.Char(string="Activation Token") otp_code = fields.Char(string='OTP Code') otp_create_date = fields.Datetime(string='OTP Create Date') + payment_terms_id = fields.Many2one('account.payment.term', related='partner_id.property_payment_term_id', string='Payment Terms') user_company_name = fields.Char(string="User Company Name") diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 16a1f415..aa5443c5 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -88,6 +88,8 @@ class SaleOrder(models.Model): voucher_id = fields.Many2one(comodel_name='voucher', string='Voucher', copy=False) applied_voucher_id = fields.Many2one(comodel_name='voucher', string='Applied Voucher', copy=False) amount_voucher_disc = fields.Float(string='Voucher Discount') + applied_voucher_shipping_id = fields.Many2one(comodel_name='voucher', string='Applied Voucher', copy=False) + amount_voucher_shipping_disc = fields.Float(string='Voucher Discount') source_id = fields.Many2one('utm.source', 'Source', domain="[('id', 'in', [32, 59, 60, 61])]", required=True) estimated_arrival_days = fields.Integer('Estimated Arrival Days', default=0) email = fields.Char(string='Email') @@ -109,6 +111,45 @@ class SaleOrder(models.Model): date_driver_departure = fields.Datetime(string='Departure Date', compute='_compute_date_kirim', copy=False) note_website = fields.Char(string="Note Website") use_button = fields.Boolean(string='Using Calculate Selling Price', copy=False) + voucher_shipping_id = fields.Many2one(comodel_name='voucher', string='Voucher Shipping', copy=False) + margin_after_delivery_purchase = fields.Float(string='Margin After Delivery Purchase', compute='_compute_margin_after_delivery_purchase') + percent_margin_after_delivery_purchase = fields.Float(string='% Margin After Delivery Purchase', compute='_compute_margin_after_delivery_purchase') + purchase_delivery_amt = fields.Float(string='Purchase Delivery Amount', compute='_compute_purchase_delivery_amount') + type_promotion = fields.Char(string='Type Promotion', compute='_compute_type_promotion') + + def _compute_type_promotion(self): + for rec in self: + promotion_types = [] + for promotion in rec.order_promotion_ids: + for line_program in promotion.program_line_id: + if line_program.promotion_type: + promotion_types.append(dict(line_program._fields['promotion_type'].selection).get(line_program.promotion_type)) + + # Removing duplicates by converting to a set, then back to a list + rec.type_promotion = ', '.join(sorted(set(promotion_types))) + + def _compute_purchase_delivery_amount(self): + for order in self: + match = self.env['purchase.order.sales.match'] + result2 = match.search([ + ('sale_id.id', '=', order.id) + ]) + delivery_amt = 0 + for res in result2: + delivery_amt = res.delivery_amt + order.purchase_delivery_amt = delivery_amt + + def _compute_margin_after_delivery_purchase(self): + for order in self: + order.margin_after_delivery_purchase = order.total_margin - order.purchase_delivery_amt + if order.amount_untaxed == 0: + order.percent_margin_after_delivery_purchase = 0 + continue + if order.shipping_cost_covered == 'indoteknik': + delivery_amt = order.delivery_amt + else: + delivery_amt = 0 + order.percent_margin_after_delivery_purchase = round((order.margin_after_delivery_purchase / (order.amount_untaxed-delivery_amt-order.fee_third_party)) * 100, 2) def _compute_date_kirim(self): for rec in self: @@ -630,6 +671,9 @@ class SaleOrder(models.Model): if not order.client_order_ref and order.create_date > datetime(2024, 6, 27): raise UserError("Customer Reference kosong, di isi dengan NO PO jika PO tidak ada mohon ditulis Tanpa PO") + + if not order.commitment_date and order.create_date > datetime(2024, 9, 12): + raise UserError("Expected Delivery Date kosong, wajib diisi") if order.validate_partner_invoice_due(): return self._create_notification_action('Notification', 'Terdapat invoice yang telah melewati batas waktu, mohon perbarui pada dokumen Due Extension') @@ -743,7 +787,7 @@ class SaleOrder(models.Model): delivery_amt = order.delivery_amt else: delivery_amt = 0 - order.total_percent_margin = round((order.total_margin / (order.amount_untaxed-delivery_amt)) * 100, 2) + order.total_percent_margin = round((order.total_margin / (order.amount_untaxed-delivery_amt-order.fee_third_party)) * 100, 2) # order.total_percent_margin = round((order.total_margin / (order.amount_untaxed)) * 100, 2) @api.onchange('sales_tax_id') @@ -780,6 +824,28 @@ class SaleOrder(models.Model): self.apply_voucher() + def action_apply_voucher_shipping(self): + for line in self.order_line: + if line.order_promotion_id: + raise UserError('Voucher tidak dapat digabung dengan promotion program') + + voucher = self.voucher_shipping_id + if voucher.limit > 0 and voucher.count_order >= voucher.limit: + raise UserError('Voucher tidak dapat digunakan karena sudah habis digunakan') + + partner_voucher_orders = [] + for order in voucher.order_ids: + if order.partner_id.id == self.partner_id.id: + partner_voucher_orders.append(order) + + if voucher.limit_user > 0 and len(partner_voucher_orders) >= voucher.limit_user: + raise UserError('Voucher tidak dapat digunakan karena Customer ini sudah menghabiskan kuota voucher') + + if self.pricelist_id.id in [x.id for x in voucher.excl_pricelist_ids]: + raise UserError('Voucher tidak dapat digunakan karena pricelist ini tidak berlaku pada voucher') + + self.apply_voucher_shipping() + def apply_voucher(self): order_line = [] for line in self.order_line: @@ -821,6 +887,29 @@ class SaleOrder(models.Model): self.amount_voucher_disc = voucher['discount']['all'] self.applied_voucher_id = self.voucher_id + def apply_voucher_shipping(self): + for order in self: + delivery_amt = order.delivery_amt + voucher = order.voucher_shipping_id + + if voucher: + max_discount_amount = voucher.discount_amount + voucher_type = voucher.discount_type + + if voucher_type == 'fixed_price': + discount = max_discount_amount + elif voucher_type == 'percentage': + discount = delivery_amt * (max_discount_amount / 100) + + delivery_amt -= discount + + delivery_amt = max(delivery_amt, 0) + + order.delivery_amt = delivery_amt + + order.amount_voucher_shipping_disc = discount + order.applied_voucher_shipping_id = order.voucher_id.id + def cancel_voucher(self): self.applied_voucher_id = False self.amount_voucher_disc = 0 @@ -829,6 +918,11 @@ class SaleOrder(models.Model): line.discount = line.initial_discount line.initial_discount = False + def cancel_voucher_shipping(self): + self.delivery_amt + self.amount_voucher_shipping_disc + self.applied_voucher_shipping_id = False + self.amount_voucher_shipping_disc = 0 + def action_web_approve(self): if self.env.uid != self.partner_id.user_id.id: raise UserError('You are not authorized to approve this order. Only %s can approve this order.' % self.partner_id.user_id.name) diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index a64a744c..50438dbe 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -348,7 +348,7 @@ class SaleOrderLine(models.Model): def validate_line(self): for line in self: - if line.product_id.id in [385544, 224484]: + if line.product_id.id in [385544, 224484, 417724]: raise UserError('Produk Sementara Tidak Bisa Di Confirm atau Ask Approval') if not line.product_id or line.product_id.type == 'service': continue diff --git a/indoteknik_custom/models/solr/__init__.py b/indoteknik_custom/models/solr/__init__.py index 606c0035..dafd5a1e 100644 --- a/indoteknik_custom/models/solr/__init__.py +++ b/indoteknik_custom/models/solr/__init__.py @@ -10,4 +10,5 @@ from . import x_banner_banner from . import product_public_category from . import x_banner_category from . import promotion_program -from . import promotion_program_line
\ No newline at end of file +from . import promotion_program_line +from . import website_categories_management
\ No newline at end of file diff --git a/indoteknik_custom/models/solr/product_template.py b/indoteknik_custom/models/solr/product_template.py index 6f76c529..d8dec47c 100644 --- a/indoteknik_custom/models/solr/product_template.py +++ b/indoteknik_custom/models/solr/product_template.py @@ -1,4 +1,5 @@ from datetime import datetime +from bs4 import BeautifulSoup from odoo import api, fields, models @@ -78,6 +79,9 @@ class ProductTemplate(models.Model): is_in_bu = bool(stock_quant) + cleaned_desc = BeautifulSoup(template.website_description or '', "html.parser").get_text() + website_description = template.website_description if cleaned_desc else '' + document = solr_model.get_doc('product', template.id) document.update({ "id": template.id, @@ -101,9 +105,11 @@ class ProductTemplate(models.Model): "search_rank_i": template.search_rank, "search_rank_weekly_i": template.search_rank_weekly, "category_id_ids": category_ids, # ID kategori sebagai string yang dipisahkan koma + "category_parent_ids": self.get_category_hierarchy_ids(category_ids), # ID kategori sebagai string yang dipisahkan koma "category_name_s": ', '.join(category_names), # Nama kategori sebagai string yang dipisahkan koma "category_name": category_names, # Nama kategori sebagai list "description_t": template.website_description or '', + "description_clean_t": cleaned_desc or '', 'has_product_info_b': True, 'publish_b': not template.unpublished, 'sni_b': template.unpublished, @@ -127,6 +133,36 @@ class ProductTemplate(models.Model): if not document.get('has_price_info_b'): template._sync_price_to_solr() + def get_category_hierarchy_ids(self, category_id): + """ + Function to get category hierarchy IDs including the category itself and its parents. + + Args: + category_id (int): The ID of the category you want to retrieve. + env (Environment): The Odoo environment. + + Returns: + list: A list of IDs for the category and its parents. + """ + category_ids = [] + + def traverse_category(cat_id): + # Retrieve category object based on ID + category = self.env['product.public.category'].browse(cat_id) + + # Add the current category ID to the list + category_ids.append(category.id) + + # If there is a parent category, traverse upwards + if category.parent_id: + traverse_category(category.parent_id.id) + + # Start traversal from the initial category + traverse_category(category_id) + + # Reverse the list to get the hierarchy from top level to the current level + return list(reversed(category_ids)) + def _sync_price_to_solr(self): solr_model = self.env['apache.solr'] TIER_NUMBERS = ['1_v2', '2_v2', '3_v2', '4_v2', '5_v2'] diff --git a/indoteknik_custom/models/solr/promotion_program_line.py b/indoteknik_custom/models/solr/promotion_program_line.py index 4b0e67f6..3e3a2a28 100644 --- a/indoteknik_custom/models/solr/promotion_program_line.py +++ b/indoteknik_custom/models/solr/promotion_program_line.py @@ -37,6 +37,9 @@ class PromotionProgramLine(models.Model): promotion_type = rec._res_promotion_type() + # Gathering all categories + category_names = [category.name for category in rec.product_ids.product_id.public_categ_ids] + # Set sequence_i to None if rec.sequence is 0 sequence_value = None if rec.sequence == 0 else rec.sequence @@ -57,7 +60,9 @@ class PromotionProgramLine(models.Model): 'free_products_s': json.dumps(free_products), 'total_qty_i': sum([x.qty for x in rec.product_ids] + [x.qty for x in rec.free_product_ids]), 'total_qty_sold_f': [x.product_id.qty_sold for x in rec.product_ids], - 'active_b': rec.active + 'active_b': rec.active, + "manufacture_name_s": rec.product_ids.product_id.x_manufacture.x_name or '', + "category_name": category_names, }) self.solr().add([document]) diff --git a/indoteknik_custom/models/solr/website_categories_management.py b/indoteknik_custom/models/solr/website_categories_management.py new file mode 100644 index 00000000..0a40a356 --- /dev/null +++ b/indoteknik_custom/models/solr/website_categories_management.py @@ -0,0 +1,114 @@ +from odoo import models, fields, api +from datetime import datetime +import json + +class WebsiteCategoriesHomepage(models.Model): + _inherit = 'website.categories.management' + + last_update_solr = fields.Datetime('Last Update Solr') + + def solr(self): + """Returns the Solr connection object.""" + return self.env['apache.solr'].connect('category_management') + + def update_last_update_solr(self): + """Updates the last sync time for the record.""" + self.last_update_solr = datetime.utcnow() + + def _create_solr_queue(self, function_name): + """Creates unique Solr queue for each record.""" + for rec in self: + self.env['apache.solr.queue'].create_unique({ + 'res_model': self._name, + 'res_id': rec.id, + 'function_name': function_name + }) + + @api.constrains('status') + def _create_solr_queue_sync_status(self): + """Triggers Solr sync when the status changes.""" + self._create_solr_queue('_sync_status_category_homepage_solr') + + @api.constrains('category_id', 'category_id2', 'sequence') + def _create_solr_queue_sync_category_homepage(self): + """Triggers Solr sync when categories or sequence change.""" + self._create_solr_queue('_sync_category_management_to_solr') + + def action_sync_to_solr(self): + """Manual action to sync selected categories to Solr.""" + category_ids = self.env.context.get('active_ids', []) + categories = self.search([('id', 'in', category_ids)]) + categories._create_solr_queue('_sync_category_management_to_solr') + + def unlink(self): + """Overrides unlink method to remove records from Solr.""" + for rec in self: + self.solr().delete(rec.id) + self.solr().optimize() + self.solr().commit() + return super(WebsiteCategoriesHomepage, self).unlink() + + def _sync_status_category_homepage_solr(self): + """Syncs status to Solr or deletes if not active.""" + for rec in self: + if rec.status == 'tayang': + rec._sync_category_management_to_solr() + else: + rec.unlink() + + def _sync_category_management_to_solr(self): + """Syncs categories (Level 1, 2, and 3) to Solr.""" + solr_model = self.env['apache.solr'] + + for category in self: + if category.status != 'tayang': + continue + + # Prepare Level 1 document + document = { + 'id': category.id, + 'sequence_i': category.sequence or '', + 'category_id_i': category.category_id.id, + 'name_s': category.category_id.name, + 'numFound_i': len(category.category_id.product_tmpl_ids), + 'image_s': self.env['ir.attachment'].api_image( + 'product.public.category', 'image_1920', category.category_id.id + ), + 'categories': [] + } + + # Prepare Level 2 documents + for category_level_2 in category.line_ids.mapped('category_id2'): + level_2_doc = { + 'id_level_2': category_level_2.id, + 'name': category_level_2.name, + 'numFound': len(category_level_2.product_tmpl_ids), + 'image': self.env['ir.attachment'].api_image( + 'product.public.category', 'image_1920', category_level_2.id + ), + 'child_frontend_id_i': [] + } + + # Prepare Level 3 documents + for category_level_3 in category_level_2.child_frontend_id2: + level_3_doc = { + 'id_level_3': category_level_3.id, + 'name': category_level_3.name, + 'numFound': len(category_level_3.product_tmpl_ids), + 'image': self.env['ir.attachment'].api_image( + 'product.public.category', 'image_1920', category_level_3.id + ), + } + level_2_doc['child_frontend_id_i'].append(json.dumps(level_3_doc)) + + # Add Level 2 document to Level 1 + document['categories'].append(json.dumps(level_2_doc)) + + # Sync document with Solr + self.solr().add([document]) + category.update_last_update_solr() + + # Commit and optimize Solr changes + self.solr().commit() + self.solr().optimize() + diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 6083e9e7..3dd960e2 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -126,6 +126,8 @@ class StockPicking(models.Model): def do_unreserve(self): res = super(StockPicking, self).do_unreserve() + if not self.env.user.is_purchasing_manager: + raise UserError('Hanya Purchasing Manager yang bisa Unreserve') current_time = datetime.datetime.utcnow() self.date_unreserve = current_time return res @@ -371,6 +373,9 @@ class StockPicking(models.Model): if self.picking_type_id.id == 28 and not self.env.user.is_logistic_approver: raise UserError("Harus di Approve oleh Logistik") + + if self.location_dest_id.id == 47 and not self.env.user.is_purchasing_manager: + raise UserError("Transfer ke gudang selisih harus di approve Rafly Hanggara") if self.group_id.sale_id: if self.group_id.sale_id.payment_link_midtrans: diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py index f7305999..37c97338 100644 --- a/indoteknik_custom/models/voucher.py +++ b/indoteknik_custom/models/voucher.py @@ -146,7 +146,7 @@ class Voucher(models.Model): def calc_discount_amount(self, total): result = { 'all': 0, 'brand': {} } - if self.apply_type == 'all': + if self.apply_type in ['all', 'shipping']: if total['all'] < self.min_purchase_amount: return result diff --git a/indoteknik_custom/models/website_categories_management.py b/indoteknik_custom/models/website_categories_management.py index 208b07a2..e430ef5f 100644 --- a/indoteknik_custom/models/website_categories_management.py +++ b/indoteknik_custom/models/website_categories_management.py @@ -6,8 +6,8 @@ class WebsiteCategoriesManagement(models.Model): _rec_name = 'category_id' category_id = fields.Many2one('product.public.category', string='Category Level 1', help='table ecommerce category', domain=lambda self: self._get_default_category_domain()) - category_id2 = fields.Many2many(comodel_name='product.public.category', relation='website_categories_category_id2_rel',column1='website_categories_homepage_id', column2='product_public_category_id', string='Category Level 2', copy=False) sequence = fields.Integer(string='Sequence') + line_ids = fields.One2many('website.categories.management.line', 'management_id', string='Category Level 2 Lines', auto_join=True) status = fields.Selection([ ('tayang', 'Tayang'), ('tidak_tayang', 'Tidak Tayang') @@ -17,11 +17,11 @@ class WebsiteCategoriesManagement(models.Model): def _onchange_category_id(self): domain = {} if self.category_id != self._origin.category_id: # Check if the category_id has changed - self.category_id2 = [(5, 0, 0)] # Clear the category_id2 field if category_id has changed + self.line_ids = [(5, 0, 0)] # Clear the lines if category_id has changed if self.category_id: - domain['category_id2'] = [('parent_frontend_id', '=', self.category_id.id)] + domain['line_ids'] = [('parent_frontend_id', '=', self.category_id.id)] else: - domain['category_id2'] = [] + domain['line_ids'] = [] return {'domain': domain} @@ -42,24 +42,30 @@ class WebsiteCategoriesManagement(models.Model): def _check_category_consistency(self): for record in self: - category_ids = record.category_id2.ids - for category in record.category_id2: - for child_category in category.child_frontend_id2: - if child_category.parent_frontend_id.id not in category_ids: + category_level2_ids = record.line_ids.mapped('category_id2.id') # Get all Category Level 2 IDs + for line in record.line_ids: + for category_level3 in line.category_id3_ids: # Loop through selected Category Level 3 + if category_level3.parent_frontend_id.id not in category_level2_ids: raise ValidationError( - f"Category Level 3 {child_category.name} bukan bagian dari category Level 2 {category.name}") + f"Category Level 3 '{category_level3.name}' bukan bagian dari Category Level 2 '{line.category_id2.name}'") def unlink(self): - for record in self.category_id2: - if record.id: + for record in self.line_ids: + if record.category_id2: related_categories = self.env['product.public.category'].search([ - ('id', 'in', record.ids) + ('id', '=', record.category_id2.id) ]) for category in related_categories: - for category3 in record.child_frontend_id2.ids: - if category3 in category.child_frontend_id2.ids: + # Iterate through the Category Level 3 related to the current Category Level 2 + for category3 in record.category_id3_ids: + # If Category Level 3 is linked to Category Level 2, remove the link + if category3.id in category.child_frontend_id2.ids: category.write({ - 'child_frontend_id2': [(3, category3)] + 'child_frontend_id2': [(3, category3.id)] + # Remove the link between Category Level 2 and Category Level 3 }) + return super(WebsiteCategoriesManagement, self).unlink() + + diff --git a/indoteknik_custom/models/website_categories_management_line.py b/indoteknik_custom/models/website_categories_management_line.py new file mode 100644 index 00000000..2f97ddfa --- /dev/null +++ b/indoteknik_custom/models/website_categories_management_line.py @@ -0,0 +1,22 @@ +from odoo import fields, models, api +from odoo.exceptions import ValidationError + +class WebsiteCategoriesManagementLine(models.Model): + _name = 'website.categories.management.line' + _order = 'sequence' + + sequence = fields.Integer(string='Sequence') + management_id = fields.Many2one('website.categories.management', string='Management Reference', required=True, ondelete='cascade') + category_id2 = fields.Many2one('product.public.category', string='Category Level 2', required=True,) + category_id3_ids = fields.Many2many('product.public.category', string='Category Level 3') + + @api.onchange('category_id2') + def _onchange_category_id2(self): + """ Update domain for category_id3_ids based on category_id2 """ + if self.category_id2: + domain_category_id3_ids = [('parent_frontend_id', '=', self.category_id2.id)] + else: + domain_category_id3_ids = [] + + return {'domain': {'category_id3_ids': domain_category_id3_ids}} + diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index d9352abb..b0cf47f7 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -91,7 +91,7 @@ class WebsiteUserCart(models.Model): products = carts.get_products() return products - def get_user_checkout(self, user_id, voucher=False, source=False): + def get_user_checkout(self, user_id, voucher=False, voucher_shipping=False, source=False): products = self.get_product_by_user(user_id=user_id, selected=True, source=source) total_purchase = 0 @@ -109,12 +109,12 @@ class WebsiteUserCart(models.Model): subtotal = total_purchase - total_discount discount_voucher = 0 - if voucher: - order_line = [] + discount_voucher_shipping = 0 + order_line = [] + + if voucher or voucher_shipping: for product in products: - if product['cart_type'] == 'promotion': - continue - + if product['cart_type'] == 'promotion': continue order_line.append({ 'product_id': self.env['product.product'].browse(product['id']), 'price': product['price']['price'], @@ -122,9 +122,16 @@ class WebsiteUserCart(models.Model): 'qty': product['quantity'], 'subtotal': product['subtotal'] }) + + if voucher: voucher_info = voucher.apply(order_line) discount_voucher = voucher_info['discount']['all'] subtotal -= discount_voucher + + if voucher_shipping: + voucher_shipping_info = voucher_shipping.apply(order_line) + discount_voucher_shipping = voucher_shipping_info['discount']['all'] + tax = round(subtotal * 0.11) grand_total = subtotal + tax total_weight = sum(x['weight'] * x['quantity'] for x in products) @@ -133,6 +140,7 @@ class WebsiteUserCart(models.Model): 'total_purchase': total_purchase, 'total_discount': total_discount, 'discount_voucher': discount_voucher, + 'discount_voucher_shipping': discount_voucher_shipping, 'subtotal': subtotal, 'tax': tax, 'grand_total': round(grand_total), diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index 5e7554a5..09dbb45e 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -23,6 +23,7 @@ access_website_brand_homepage,access.website.brand.homepage,model_website_brand_ access_website_categories_homepage,access.website.categories.homepage,model_website_categories_homepage,,1,1,1,1 access_website_categories_lob,access.website.categories.lob,model_website_categories_lob,,1,1,1,1 access_website_categories_management,access.website.categories.management,model_website_categories_management,,1,1,1,1 +access_website_categories_management_line,access.website.categories.management.line,model_website_categories_management_line,,1,1,1,1 access_sales_target,access.sales.target,model_sales_target,,1,1,1,1 access_purchase_outstanding,access.purchase.outstanding,model_purchase_outstanding,,1,1,1,1 access_sales_outstanding,access.sales.outstanding,model_sales_outstanding,,1,1,1,1 diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index 93145fea..2863af57 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -85,6 +85,7 @@ </field> <field name="invoice_date_due" position="after"> <field name="new_due_date" optional="hide"/> + <field name="is_efaktur_exported" optional="hide"/> <field name="invoice_day_to_due" attrs="{'invisible': [['payment_state', 'in', ('paid', 'in_payment', 'reversed')]]}" optional="hide"/> <field name="new_invoice_day_to_due" attrs="{'invisible': [['payment_state', 'in', ('paid', 'in_payment', 'reversed')]]}" optional="hide"/> <field name="mark_upload_efaktur" optional="hide" widget="badge" diff --git a/indoteknik_custom/views/bill_receipt.xml b/indoteknik_custom/views/bill_receipt.xml index 15d82e7b..02b28ddf 100644 --- a/indoteknik_custom/views/bill_receipt.xml +++ b/indoteknik_custom/views/bill_receipt.xml @@ -13,6 +13,7 @@ <field name="resi_tukar_faktur"/> <field name="date_terima_tukar_faktur"/> <field name="shipper_faktur_id"/> + <field name="grand_total"/> </tree> </field> </record> @@ -69,6 +70,7 @@ <field name="resi_tukar_faktur"/> <field name="date_terima_tukar_faktur"/> <field name="shipper_faktur_id"/> + <field name="grand_total"/> </group> </group> <notebook> diff --git a/indoteknik_custom/views/dunning_run.xml b/indoteknik_custom/views/dunning_run.xml index 567d5e8c..522be8c9 100644 --- a/indoteknik_custom/views/dunning_run.xml +++ b/indoteknik_custom/views/dunning_run.xml @@ -13,6 +13,7 @@ <field name="resi_tukar_faktur"/> <field name="date_terima_tukar_faktur"/> <field name="shipper_faktur_id"/> + <field name="grand_total"/> </tree> </field> </record> @@ -71,12 +72,20 @@ <field name="resi_tukar_faktur"/> <field name="date_terima_tukar_faktur"/> <field name="shipper_faktur_id"/> + <field name="grand_total"/> </group> </group> <notebook> <page id="invoice_tab" string="Invoices"> <field name="dunning_line"/> </page> + <page id="others_tab" string="Others"> + <group> + <field name="is_paid" readonly="1"/> + <field name="description" readonly="1"/> + <field name="comment" readonly="1"/> + </group> + </page> </notebook> </sheet> <div class="oe_chatter"> diff --git a/indoteknik_custom/views/product_pricelist.xml b/indoteknik_custom/views/product_pricelist.xml index 0dfb69db..6eff0153 100644 --- a/indoteknik_custom/views/product_pricelist.xml +++ b/indoteknik_custom/views/product_pricelist.xml @@ -26,4 +26,18 @@ </page> </field> </record> + + <data noupdate="1"> + <record id="ir_cron_check_end_date" model="ir.cron"> + <field name="name">Pricelist: Check End Date and Update Solr</field> + <field name="interval_number">1</field> + <field name="interval_type">days</field> + <field name="numbercall">-1</field> + <field name="doall" eval="False"/> + <field name="model_id" ref="model_product_pricelist"/> + <field name="code">model._check_end_date_and_update_solr()</field> + <field name="state">code</field> + <field name="priority">55</field> + </record> + </data> </odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml index 520af5c8..b6155eea 100755 --- a/indoteknik_custom/views/product_template.xml +++ b/indoteknik_custom/views/product_template.xml @@ -8,7 +8,7 @@ <field name="arch" type="xml"> <field name="categ_id" position="after"> <field name="web_tax_id" domain="[('type_tax_use','=','sale'), ('active', '=', True)]"/> - <field name="x_manufacture"/> + <field name="x_manufacture" options="{'no_create': True}"/> <field name="x_model_product"/> <field name="kind_of"/> <field name="x_studio_field_tGhJR" widget="many2many_tags"/> @@ -21,6 +21,12 @@ <field name="desc_update_solr" readonly="1" /> <field name="last_update_solr" readonly="1" /> </field> + <field name="public_categ_ids" position="attributes"> + <attribute name="required">1</attribute> + </field> + <field name="public_categ_ids" position="attributes"> + <attribute name="options">{'no_create': True}</attribute> + </field> <page name="inventory" position="after"> <page string="Marketplace" name="marketplace"> <group> diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml index 25b7787b..ce127fdd 100755 --- a/indoteknik_custom/views/purchase_order.xml +++ b/indoteknik_custom/views/purchase_order.xml @@ -26,20 +26,26 @@ <button name="button_unlock" position="after"> <button name="delete_line" type="object" string="Delete " states="draft"/> </button> + <button name="button_unlock" position="after"> + <button name="create_bill_dp" string="Create Bill DP" type="object" class="oe_highlight" context="{'create_bill':True}" attrs="{'invisible': ['|', ('state', 'not in', ('purchase', 'done')), ('invoice_status', 'in', ('no', 'invoiced'))]}"/> + </button> <field name="date_order" position="before"> <field name="sale_order_id" attrs="{'readonly': [('state', 'not in', ['draft'])]}"/> <field name="sale_order"/> <field name="is_create_uangmuka"/> <field name="approval_status"/> - <field name="amount_total_without_service"/> </field> <field name="approval_status" position="after"> - <field name="revisi_po" attrs="{'readonly': [('state', 'not in', ['draft'])]}"/> + <field name="revisi_po" invisible="1"/> + </field> + <field name="incoterm_id" position="after"> + <field name="amount_total_without_service"/> + <field name="delivery_amt"/> </field> <field name="currency_id" position="after"> <field name="summary_qty_po"/> <field name="count_line_product"/> - <field name="payment_term_id" required="1"/> + <field name="payment_term_id" readonly="1"/> </field> <field name="amount_total" position="after"> <field name="total_margin"/> @@ -88,6 +94,7 @@ <field name="from_apo"/> <field name="approval_edit_line"/> <field name="logbook_bill_id"/> + <field name="bills_dp_id" readonly="1"/> </field> <field name="order_line" position="attributes"> @@ -229,6 +236,9 @@ <field name="product_id"/> <field name="qty_so"/> <field name="qty_po"/> + <field name="margin_item" optional="hide"/> + <field name="delivery_amt" optional="hide"/> + <field name="margin_deduct" optional="hide"/> <field name="margin_so"/> </tree> </field> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index 1257ff85..f2789254 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -32,6 +32,7 @@ <field name="delivery_amt"/> <field name="fee_third_party"/> <field name="total_percent_margin"/> + <field name="type_promotion"/> <label for="voucher_id"/> <div class="o_row"> <field name="voucher_id" id="voucher_id" attrs="{'readonly': ['|', ('state', 'not in', ['draft', 'sent']), ('applied_voucher_id', '!=', False)]}"/> @@ -43,6 +44,17 @@ attrs="{'invisible': ['|', ('applied_voucher_id', '=', False), ('state', 'not in', ['draft','sent'])]}" /> </div> + <label for="voucher_shipping_id"/> + <div class="o_row"> + <field name="voucher_shipping_id" id="voucher_shipping_id" attrs="{'readonly': ['|', ('state', 'not in', ['draft', 'sent']), ('applied_voucher_shipping_id', '!=', False)]}"/> + <field name="applied_voucher_shipping_id" invisible="1" /> + <button name="action_apply_voucher_shipping" type="object" string="Apply" confirm="Anda yakin untuk menggunakan voucher?" help="Apply the selected voucher" class="btn-link mb-1 px-0" icon="fa-plus" + attrs="{'invisible': ['|', '|', ('voucher_id', '=', False), ('state', 'not in', ['draft', 'sent']), ('applied_voucher_shipping_id', '!=', False)]}" + /> + <button name="cancel_voucher_shipping" type="object" string="Cancel" confirm="Anda yakin untuk membatalkan penggunaan voucher?" help="Cancel applied voucher" class="btn-link mb-1 px-0" icon="fa-times" + attrs="{'invisible': ['|', ('applied_voucher_shipping_id', '=', False), ('state', 'not in', ['draft','sent'])]}" + /> + </div> <button name="calculate_selling_price" string="Calculate Selling Price" type="object" @@ -58,6 +70,8 @@ <field name="tag_ids" position="after"> <field name="eta_date" readonly="1"/> <field name="flash_sale"/> + <field name="margin_after_delivery_purchase"/> + <field name="percent_margin_after_delivery_purchase"/> </field> <field name="analytic_account_id" position="after"> <field name="customer_type" required="1"/> @@ -112,6 +126,7 @@ "/> <field name="purchase_tax_id" attrs="{'readonly': [('parent.approval_status', '!=', False)]}" domain="[('type_tax_use','=','purchase')]"/> <field name="item_percent_margin"/> + <field name="item_margin" optional="hide"/> <field name="note" optional="hide"/> <field name="note_procurement" optional="hide"/> <field name="vendor_subtotal" optional="hide"/> @@ -138,6 +153,11 @@ <field class="mb-0" name="amount_voucher_disc" string="Voucher" readonly="1"/> <div class="text-right mb-2"><small>*Hanya informasi</small></div> </div> + <label for="amount_voucher_shipping_disc" string="Voucher Shipping" /> + <div> + <field class="mb-0" name="amount_voucher_shipping_disc" string="Voucher Shipping" readonly="1"/> + <div class="text-right mb-2"><small>*Hanya informasi</small></div> + </div> <field name="total_margin"/> <field name="total_percent_margin"/> </field> diff --git a/indoteknik_custom/views/website_categories_management.xml b/indoteknik_custom/views/website_categories_management.xml index 648814e2..6ad85944 100644 --- a/indoteknik_custom/views/website_categories_management.xml +++ b/indoteknik_custom/views/website_categories_management.xml @@ -29,16 +29,16 @@ <group> <field name="sequence"/> <field name="category_id"/> - <field name="category_id2" widget="many2many_tags"/> <field name="status"/> </group> </group> <notebook> - <page string="Detail category"> - <field name="category_id2"> + <page string="Category Level 2 Lines"> + <field name="line_ids"> <tree editable="bottom"> - <field name="name"/> - <field name="child_frontend_id2" widget="many2many_tags"/> + <field name="category_id2" domain="[('parent_frontend_id', '=', parent.category_id)]"/> <!-- Category Level 2 --> + <field name="category_id3_ids" widget="many2many_tags"/> <!-- Category Level 3 --> + <field name="sequence" widget="handle" /> </tree> </field> </page> @@ -48,13 +48,13 @@ </field> </record> -<!-- <record id="ir_actions_server_website_categories_management_sync_to_solr" model="ir.actions.server">--> -<!-- <field name="name">Sync to solr</field>--> -<!-- <field name="model_id" ref="indoteknik_custom.model_website_categories_management"/>--> -<!-- <field name="binding_model_id" ref="indoteknik_custom.model_website_categories_management"/>--> -<!-- <field name="state">code</field>--> -<!-- <field name="code">model.action_sync_to_solr()</field>--> -<!-- </record>--> + <record id="ir_actions_server_website_categories_management_sync_to_solr" model="ir.actions.server"> + <field name="name">Sync to solr</field> + <field name="model_id" ref="indoteknik_custom.model_website_categories_management"/> + <field name="binding_model_id" ref="indoteknik_custom.model_website_categories_management"/> + <field name="state">code</field> + <field name="code">model.action_sync_to_solr()</field> + </record> <menuitem id="website_categories_management" |
