diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-11-10 13:40:58 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-11-10 13:40:58 +0700 |
| commit | 2aee5a44abbe36961dfe23cc3d656aa48e11e0f9 (patch) | |
| tree | 8ec2b6552aaef4e14539aa52ed796552e24180d6 | |
| parent | 6a87e59e7220bdfa78e98b23003ccc4ef41bd0ce (diff) | |
| parent | b4e74170aeaf00937f78e5af9047218ddb17516c (diff) | |
Merge branch 'production' into change/feature/promotion-program
51 files changed, 1326 insertions, 330 deletions
diff --git a/indoteknik_api/controllers/api_v1/cart.py b/indoteknik_api/controllers/api_v1/cart.py index 88fa9f88..8ef2c1c1 100644 --- a/indoteknik_api/controllers/api_v1/cart.py +++ b/indoteknik_api/controllers/api_v1/cart.py @@ -14,8 +14,9 @@ class Cart(controller.Controller): user_id = int(user_id) limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) - query = [('user_id', '=', user_id), ('source', '=', 'add_to_cart')] + query = [('user_id', '=', user_id)] carts = user_cart.search(query, limit=limit, offset=offset, order='create_date desc') + carts.write({'source': 'add_to_cart'}) data = { 'product_total': user_cart.search_count(query), 'products': carts.with_context(price_for="web").get_products() @@ -26,7 +27,7 @@ class Cart(controller.Controller): @controller.Controller.must_authorized() def get_cart_count_by_user_id(self, user_id, **kw): user_id = int(user_id) - query = [('user_id', '=', user_id), ('source', '=', 'add_to_cart')] + query = [('user_id', '=', user_id)] carts = request.env['website.user.cart'].search_count(query) return self.response(carts) @@ -77,7 +78,7 @@ class Cart(controller.Controller): data_to_update['source'] = source result = {} - if cart and source in (None, 'add_to_cart'): + if cart: # Update existing cart entry cart.write(data_to_update) result['id'] = cart.id diff --git a/indoteknik_api/controllers/api_v1/category.py b/indoteknik_api/controllers/api_v1/category.py index 3c5766e2..44a60bc9 100644 --- a/indoteknik_api/controllers/api_v1/category.py +++ b/indoteknik_api/controllers/api_v1/category.py @@ -120,4 +120,19 @@ class Category(controller.Controller): 'name': category.name }) return self.response(data) -
\ No newline at end of file + + @http.route(prefix + 'category/<id>/category-breadcrumb', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_category_parents_by_id(self, id, **kw): + categories = [] + + category = request.env['product.public.category'].search([('id', '=', int(id))], limit=1) + if not category: + return self.response(code=400, description='Category not found') + + while category: + categories.append({'id': category.id, 'name': category.name}) + category = category.parent_frontend_id + + categories.reverse() + return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')])
\ No newline at end of file diff --git a/indoteknik_api/controllers/api_v1/download.py b/indoteknik_api/controllers/api_v1/download.py index d9353896..54b09372 100644 --- a/indoteknik_api/controllers/api_v1/download.py +++ b/indoteknik_api/controllers/api_v1/download.py @@ -28,7 +28,7 @@ class Download(controller.Controller): return rest_api.response_attachment({ 'content': pdf, 'mimetype': 'application/pdf', - 'filename': account_move[0]['name'] + 'filename': account_move[0]['name'] + '.pdf' }) @http.route(PREFIX + 'download/tax-invoice/<id>/<token>', auth='none', method=['GET']) @@ -47,6 +47,6 @@ class Download(controller.Controller): 'content': attachment['datas'], 'decode_content': True, 'mimetype': attachment['mimetype'], - 'filename': account_move[0]['name'], + 'filename': account_move[0]['name'] + '.pdf', }) return self.response('Dokumen tidak ditemukan', code=404) diff --git a/indoteknik_api/controllers/api_v1/product.py b/indoteknik_api/controllers/api_v1/product.py index 2cbdede7..1b698f26 100644 --- a/indoteknik_api/controllers/api_v1/product.py +++ b/indoteknik_api/controllers/api_v1/product.py @@ -2,7 +2,10 @@ from .. import controller from odoo import http from odoo.http import request from datetime import datetime, timedelta -import ast, logging, math, json +import ast +import logging +import math +import json _logger = logging.getLogger(__name__) @@ -10,20 +13,43 @@ _logger = logging.getLogger(__name__) class Product(controller.Controller): prefix = '/api/v1/' + @http.route(prefix + 'product/<id>/category-breadcrumb', auth='public', methods=['GET', 'OPTIONS']) + @controller.Controller.must_authorized() + def get_product_categories_by_id(self, id, **kw): + categories = [] + + product = request.env['product.template'].search( + [('id', '=', int(id))], limit=1) + if not product: + return self.response(code=400, description='Product not found') + + if len(product.public_categ_ids) == 0: + return self.response(categories) + + category = product.public_categ_ids[0] + while category: + categories.append({'id': category.id, 'name': category.name}) + category = category.parent_frontend_id + + categories.reverse() + return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')]) + @http.route(prefix + 'product_variant/<id>/stock', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_template_stock_by_id(self, **kw): id = int(kw.get('id')) date_7_days_ago = datetime.now() - timedelta(days=7) - product = request.env['product.product'].search([('id', '=', id)], limit=1) - product_sla = request.env['product.sla'].search([('product_variant_id', '=', id)], limit=1) + product = request.env['product.product'].search( + [('id', '=', id)], limit=1) + product_sla = request.env['product.sla'].search( + [('product_variant_id', '=', id)], limit=1) stock_vendor = request.env['stock.vendor'].search([ ('product_variant_id', '=', id), ('write_date', '>=', date_7_days_ago.strftime("%Y-%m-%d %H:%M:%S")) ], limit=1) qty_available = product.qty_onhand_bandengan - + qty = 0 sla_date = '-' @@ -33,22 +59,23 @@ class Product(controller.Controller): qty_vendor = math.ceil(float(qty_vendor)) total_excell = qty_vendor - is_altama_product = product.x_manufacture.id in [10,122,89] + is_altama_product = product.x_manufacture.id in [10, 122, 89] if is_altama_product: try: # Qty Altama - qty_altama = request.env['product.template'].get_stock_altama(product.default_code) + qty_altama = request.env['product.template'].get_stock_altama( + product.default_code) qty_altama -= int(qty_altama * 0.1) qty_altama = math.ceil(float(qty_altama)) - total_adem = qty_altama - + total_adem = qty_altama + if qty_available > 0: qty = qty_available + total_adem + total_excell sla_date = '1 Hari' elif qty_altama > 0 or qty_vendor > 0: qty = total_adem if qty_altama > 0 else total_excell sla_date = '2-4 Hari' - else: + else: sla_date = '3-7 Hari' except: print('error') @@ -56,10 +83,9 @@ class Product(controller.Controller): if qty_available > 0: qty = qty_available sla_date = product_sla.sla or '-' - elif qty_vendor > 0: + elif qty_vendor > 0: qty = total_excell sla_date = '2-4 Hari' - data = { 'qty': qty, @@ -68,14 +94,14 @@ class Product(controller.Controller): return self.response(data, headers=[('Cache-Control', 'max-age=600, private')]) - @http.route(prefix + 'product/template/price/<id>', auth='public', methods=['GET', 'OPTIONS']) def get_product_template_price_by_id(self, **kw): if not self.authenticate(): return self.response(code=401, description='Unauthorized') id = kw.get('id') partner_id = int(kw.get('partner_id', 0)) - product_template = request.env['product.template'].search([('id', '=', id)], limit=1) + product_template = request.env['product.template'].search( + [('id', '=', id)], limit=1) data = { 'price_include': product_template.product_variant_id._get_website_price_include_tax(), @@ -106,14 +132,15 @@ class Product(controller.Controller): data.update(start_from) return self.response(data, headers=[('Cache-Control', 'max-age=180, private')]) - + @http.route(prefix + 'product/product/price/<id>', auth='public', methods=['GET', 'OPTIONS']) def get_product_product_price_by_id(self, **kw): if not self.authenticate(): return self.response(code=401, description='Unauthorized') id = kw.get('id') - partner_id = int(kw.get('partner_id', 0)) - product_product = request.env['product.product'].search([('id', '=', id)], limit=1) + partner_id = int(kw.get('partner_id', 0)) + product_product = request.env['product.product'].search( + [('id', '=', id)], limit=1) data = { 'price_include': product_product._get_website_price_include_tax(), @@ -132,7 +159,8 @@ class Product(controller.Controller): is_brand_only = int(kw.get('is_brand_only', 0)) base_url = request.env['ir.config_parameter'].get_param('web.base.url') - limit_new_products = request.env['ir.config_parameter'].get_param('limit.new.product') + limit_new_products = request.env['ir.config_parameter'].get_param( + 'limit.new.product') limit_new_products = int(limit_new_products) # current_time = datetime.now() # delta_time = current_time - timedelta(days=30) @@ -147,8 +175,9 @@ class Product(controller.Controller): ('x_manufacture', '!=', False), # ('create_date', '>=', delta_time), ] - new_products = request.env['product.template'].search(query_products, order='create_date desc', limit=limit_new_products) - brands = [] + new_products = request.env['product.template'].search( + query_products, order='create_date desc', limit=limit_new_products) + brands = [] for product in new_products: brands.append(product.x_manufacture) brands = list(dict.fromkeys(brands)) @@ -179,11 +208,13 @@ class Product(controller.Controller): ('x_manufacture', '!=', False), # ('create_date', '>=', delta_time), ] - count_products = request.env['product.template'].search_count(query) + count_products = request.env['product.template'].search_count( + query) if count_products < 6: _logger.info('Brand Skipped %s' % brand.x_name) continue - products = request.env['product.template'].search(query, order='create_date desc', limit=12) + products = request.env['product.template'].search( + query, order='create_date desc', limit=12) data.append({ 'manufacture_id': brand.id, 'sequence': brand.sequence if brand.sequence else count, @@ -205,18 +236,19 @@ class Product(controller.Controller): categories = kw.get('categories') promotions = kw.get('promotions') ready_stock = kw.get('ready_stock') - - require_betweens = ['name', 'manufactures', 'categories', 'ready_stock', 'promotions'] - is_fulfill = False + + require_betweens = ['name', 'manufactures', + 'categories', 'ready_stock', 'promotions'] + is_fulfill = False for required in require_betweens: if kw.get(required): is_fulfill = True - + if not is_fulfill: return self.response(code=400, description='name or manufactures or categories or ready_stock or promotions is required') - + query = [('sale_ok', '=', True)] - + if name: name = '%' + name.replace(' ', '%') + '%' query += [ @@ -224,44 +256,49 @@ class Product(controller.Controller): ('default_code', 'ilike', name), ('name', 'ilike', name), ] - + if manufactures: - query.append(('x_manufacture', 'in', [int(x) for x in manufactures.split(',')])) - + query.append(('x_manufacture', 'in', [ + int(x) for x in manufactures.split(',')])) + if categories: - query.append(('public_categ_ids', 'child_of', [int(x) for x in categories.split(',')])) - + query.append(('public_categ_ids', 'child_of', [ + int(x) for x in categories.split(',')])) + if ready_stock == '1': query.append(('virtual_qty', '>', 0)) - + if promotions: - coupon_programs = request.env['coupon.program'].search([('id', 'in', promotions.split(','))]) - promotion_query = [x for coupon_program in coupon_programs for x in ast.literal_eval(coupon_program.rule_products_domain)] + coupon_programs = request.env['coupon.program'].search( + [('id', 'in', promotions.split(','))]) + promotion_query = [x for coupon_program in coupon_programs for x in ast.literal_eval( + coupon_program.rule_products_domain)] query += promotion_query - + price_from = kw.get('price_from') if price_from and int(price_from): query.append(('web_price_sorting', '>=', int(price_from))) - + price_to = kw.get('price_to') if price_to and int(price_to): query.append(('web_price_sorting', '<=', int(price_to))) - + product_variants = request.env['product.product'].search(query) product_variant_ids = [x.id for x in product_variants] - + query = [('product_variant_ids', 'in', product_variant_ids)] limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) order = self.get_product_default_order(kw.get('order')) - - product_templates = request.env['product.template'].search(query, limit=limit, offset=offset, order=order) + + product_templates = request.env['product.template'].search( + query, limit=limit, offset=offset, order=order) data = { 'product_total': request.env['product.template'].search_count(query), 'products': [request.env['product.template'].api_single_response(x) for x in product_templates] } return self.response(data) - + @http.route(prefix + 'product/solr', auth='public', methods=['GET']) @controller.Controller.must_authorized() def get_product_solr(self, **kw): @@ -269,10 +306,10 @@ class Product(controller.Controller): solr_flag = kw.get('flag') limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) - + if not solr_flag: return self.response(code=400, description='flag is required') - + query = [ ('sale_ok', '=', True), ('solr_flag', '=', int(solr_flag)) @@ -284,13 +321,14 @@ class Product(controller.Controller): ('default_code', 'ilike', name), ('name', 'ilike', name), ] - product_templates = request.env['product.template'].search(query, limit=limit, offset=offset) + product_templates = request.env['product.template'].search( + query, limit=limit, offset=offset) data = { 'product_total': request.env['product.template'].search_count(query), 'products': [request.env['product.template'].api_single_response(x, with_detail='SOLR') for x in product_templates] } return self.response(data) - + @http.route(prefix + 'product/<id>', auth='public', methods=['GET']) @controller.Controller.must_authorized() def get_product_by_id(self, **kw): @@ -300,53 +338,60 @@ class Product(controller.Controller): data = [] id = [int(x) for x in id.split(',')] - product_templates = request.env['product.template'].search([('id', 'in', id)]) + product_templates = request.env['product.template'].search( + [('id', 'in', id)]) if product_templates: - data = [request.env['product.template'].api_single_response(x, with_detail='DEFAULT') for x in product_templates] - + data = [request.env['product.template'].api_single_response( + x, with_detail='DEFAULT') for x in product_templates] + return self.response(data) - + @http.route(prefix + 'product/<id>/similar', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_similar_by_id(self, **kw): id = kw.get('id') if not id: return self.response(code=400, description='id is required') - + id = int(id) - product_template = request.env['product.template'].search([('id', '=', id)]) - - if not product_template: return self.response([]) - + product_template = request.env['product.template'].search( + [('id', '=', id)]) + + if not product_template: + return self.response([]) + query = [('id', '!=', id)] if product_template.x_manufacture: - query.append(('x_manufacture', '=', product_template.x_manufacture.id)) + query.append( + ('x_manufacture', '=', product_template.x_manufacture.id)) if product_template.public_categ_ids: - query.append(('public_categ_ids', 'in', [x.id for x in product_template.public_categ_ids])) + query.append(('public_categ_ids', 'in', [ + x.id for x in product_template.public_categ_ids])) if len(query) == 2: query.insert(0, '|') - + limit = int(kw.get('limit', 0)) offset = int(kw.get('offset', 0)) order = self.get_product_default_order(kw.get('order')) - product_templates = request.env['product.template'].search(query, limit=limit, offset=offset, order=order) - + product_templates = request.env['product.template'].search( + query, limit=limit, offset=offset, order=order) + data = { 'product_total': request.env['product.template'].search_count(query), 'products': [request.env['product.template'].api_single_response(x) for x in product_templates] } return self.response(data) - + def get_product_default_order(self, order): orders = ['product_rating desc'] if order != 'price-asc': orders.append('web_price_sorting desc') - if order == 'price-asc': + if order == 'price-asc': orders.append('web_price_sorting asc') - elif order == 'latest': + elif order == 'latest': orders.append('create_date desc') return ','.join(orders) - + @http.route(prefix + 'product/category-homepage', auth='public', methods=['GET', 'OPTIONS']) @controller.Controller.must_authorized() def get_product_category_homepage(self, **kw): @@ -356,13 +401,14 @@ class Product(controller.Controller): id = kw.get('id') if id: query = f'id:{id}' - - categories = solr_model.connect('product_category_homepage').search(query, sort='sequence_i asc').docs + + categories = solr_model.connect('product_category_homepage').search( + query, sort='sequence_i asc').docs categories = solr_model.clean_key_docs(categories) for category in categories: product_ids = category.get('product_ids', []) category.pop('product_ids', None) products = request.env['product.template'].browse(product_ids) category['products'] = products.solr_results() - - return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')])
\ No newline at end of file + + return self.response(categories, headers=[('Cache-Control', 'max-age=3600, public')]) diff --git a/indoteknik_api/controllers/api_v1/sale_order.py b/indoteknik_api/controllers/api_v1/sale_order.py index 8209c751..0f236ffb 100644 --- a/indoteknik_api/controllers/api_v1/sale_order.py +++ b/indoteknik_api/controllers/api_v1/sale_order.py @@ -181,7 +181,7 @@ class SaleOrder(controller.Controller): 'content': attachment['datas'], 'decode_content': True, 'mimetype': attachment['mimetype'], - 'filename': sale_order[0]['partner_purchase_order_name'] + 'filename': sale_order[0]['partner_purchase_order_name'] + '.pdf' }) return self.response('Dokumen tidak ditemukan', code=404) @@ -202,7 +202,7 @@ class SaleOrder(controller.Controller): return rest_api.response_attachment({ 'content': pdf, 'mimetype': 'application/pdf', - 'filename': sale_order[0]['name'] + 'filename': sale_order[0]['name'] + '.pdf' }) return self.response('Dokumen tidak ditemukan', code=404) diff --git a/indoteknik_custom/__manifest__.py b/indoteknik_custom/__manifest__.py index 6ae60345..bab86aab 100755 --- a/indoteknik_custom/__manifest__.py +++ b/indoteknik_custom/__manifest__.py @@ -98,6 +98,10 @@ 'views/sale_orders_multi_update.xml', 'views/quotation_so_multi_update.xml', 'views/stock_move_line.xml', + 'views/product_monitoring.xml', + 'views/account_bank_statement.xml', + 'views/stock_warehouse_orderpoint.xml', + 'views/customer_commision.xml', 'report/report.xml', 'report/report_banner_banner.xml', 'report/report_banner_banner2.xml', diff --git a/indoteknik_custom/models/__init__.py b/indoteknik_custom/models/__init__.py index 2eb4b9b9..37e6cce0 100755 --- a/indoteknik_custom/models/__init__.py +++ b/indoteknik_custom/models/__init__.py @@ -88,4 +88,8 @@ from . import account_account from . import account_move_line from . import stock_scheduler_compute from . import sale_orders_multi_update -from . import quotation_so_multi_update
\ No newline at end of file +from . import quotation_so_multi_update +from . import product_monitoring +from . import account_bank_statement +from . import stock_warehouse_orderpoint +from . import commision diff --git a/indoteknik_custom/models/account_bank_statement.py b/indoteknik_custom/models/account_bank_statement.py new file mode 100644 index 00000000..23008f13 --- /dev/null +++ b/indoteknik_custom/models/account_bank_statement.py @@ -0,0 +1,19 @@ +from odoo import fields, models, api, _ +from odoo.exceptions import AccessError, UserError, ValidationError + +class AccountBankStatement(models.Model): + _inherit = "account.bank.statement" + + is_edit = fields.Boolean(string='Unlock', default=False) + + def is_edited(self): + if not self.env.user.is_admin_reconcile: + raise UserError('Yang berhak hanya Mba Tania dan Iqmal Saputra') + + self.is_edit = True + + def not_edited(self): + if not self.env.user.is_admin_reconcile: + raise UserError('Yang berhak hanya Mba Tania dan Iqmal Saputra') + + self.is_edit = False
\ No newline at end of file diff --git a/indoteknik_custom/models/account_move.py b/indoteknik_custom/models/account_move.py index c3cd7ef9..fe9db583 100644 --- a/indoteknik_custom/models/account_move.py +++ b/indoteknik_custom/models/account_move.py @@ -1,6 +1,7 @@ from odoo import models, api, fields from odoo.exceptions import AccessError, UserError, ValidationError -from datetime import timedelta, date +from datetime import timedelta, date, datetime +from pytz import timezone, utc import logging import base64 import PyPDF2 @@ -13,6 +14,7 @@ _logger = logging.getLogger(__name__) class AccountMove(models.Model): _inherit = 'account.move' invoice_day_to_due = fields.Integer(string="Day to Due", compute="_compute_invoice_day_to_due") + bill_day_to_due = fields.Date(string="Day to Due", compute="_compute_bill_day_to_due") date_send_fp = fields.Datetime(string="Tanggal Kirim Faktur Pajak") last_log_fp = fields.Char(string="Log Terakhir Faktur Pajak") # use for industry business @@ -28,6 +30,7 @@ class AccountMove(models.Model): analytic_account_ids = fields.Many2many('account.analytic.account', string='Analytic Account') due_line = fields.One2many('due.extension.line', 'invoice_id', compute='_compute_due_line', string='Due Extension Lines') no_faktur_pajak = fields.Char(string='No Faktur Pajak') + date_completed = fields.Datetime(string='Date Completed') @api.onchange('efaktur_id') def change_efaktur_id(self): @@ -59,6 +62,11 @@ class AccountMove(models.Model): res = super(AccountMove, self).button_draft() if not self.env.user.is_accounting: raise UserError('Hanya Accounting yang bisa Reset to Draft') + + for rec in self.line_ids: + if rec.write_date != rec.create_date: + if rec.statement_line_id and not rec.statement_line_id.statement_id.is_edit and rec.statement_line_id.statement_id.state == 'confirm': + raise UserError('Bank Statement di Lock, Minta admin reconcile untuk unlock') return res def action_post(self): @@ -90,8 +98,10 @@ class AccountMove(models.Model): # raise UserError('Hanya Accounting yang bisa Posting') # if self._name == 'account.move': for entry in self: + entry.date_completed = datetime.utcnow() for line in entry.line_ids: line.date_maturity = entry.date + return res def _compute_invoice_day_to_due(self): @@ -103,6 +113,10 @@ class AccountMove(models.Model): invoice_day_to_due = invoice.new_due_date - date.today() invoice_day_to_due = invoice_day_to_due.days invoice.invoice_day_to_due = invoice_day_to_due + + def _compute_bill_day_to_due(self): + for rec in self: + rec.bill_day_to_due = rec.payment_schedule or rec.invoice_date_due @api.onchange('date_kirim_tukar_faktur') def change_date_kirim_tukar_faktur(self): @@ -136,4 +150,17 @@ class AccountMove(models.Model): 'move_ids': [x.id for x in self] } return action -
\ No newline at end of file + + @api.constrains('efaktur_id', 'ref', 'date', 'journal_id', 'name') + def constrains_edit(self): + for rec in self.line_ids: + if rec.statement_line_id and not rec.statement_line_id.statement_id.is_edit and rec.statement_line_id.statement_id.state == 'confirm': + raise UserError('Bank Statement di Lock, Minta admin reconcile untuk unlock') + + # def write(self, vals): + # res = super(AccountMove, self).write(vals) + # for rec in self.line_ids: + # if rec.write_date != rec.create_date: + # if rec.statement_line_id and not rec.statement_line_id.statement_id.is_edit and rec.statement_line_id.statement_id.state == 'confirm': + # raise UserError('Bank Statement di Lock, Minta admin reconcile untuk unlock') + # return res diff --git a/indoteknik_custom/models/automatic_purchase.py b/indoteknik_custom/models/automatic_purchase.py index e21b411d..502761e0 100644 --- a/indoteknik_custom/models/automatic_purchase.py +++ b/indoteknik_custom/models/automatic_purchase.py @@ -17,6 +17,7 @@ class AutomaticPurchase(models.Model): is_po = fields.Boolean(string='Is PO') purchase_match = fields.One2many('automatic.purchase.match', 'automatic_purchase_id', string='Matches', auto_join=True) vendor_id = fields.Many2one('res.partner', string='Vendor', help='boleh kosong, jika diisi, maka hanya keluar data untuk vendor tersebut') + responsible_id = fields.Many2one('res.users', string='Responsible', required=True) def create_po_from_automatic_purchase(self): if not self.purchase_lines: @@ -30,12 +31,13 @@ class AutomaticPurchase(models.Model): for vendor in vendor_ids: param_header = { 'partner_id': vendor['partner_id'][0], - 'partner_ref': 'Automatic PO', + # 'partner_ref': 'Automatic PO', '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 + 'date_order': current_time, + 'note_description': 'Automatic PO' } # new_po = self.env['purchase.order'].create([param_header]) products_vendors = self.env['automatic.purchase.line'].search([ @@ -86,7 +88,8 @@ class AutomaticPurchase(models.Model): raise UserError('Sudah digenerate sebelumnya, hapus line terlebih dahulu') query = [ - ('product_min_qty', '>', 0) + ('product_min_qty', '>', 0), + ('product_id.x_manufacture.user_id.id', '=', self.responsible_id.id) ] orderpoints = self.env['stock.warehouse.orderpoint'].search(query) count = 0 @@ -100,13 +103,20 @@ class AutomaticPurchase(models.Model): if self.vendor_id: purchase_price = self.env['purchase.pricelist'].search([ ('product_id', '=', point.product_id.id), + # ('product_id.x_manufacture.user_id.id', '=', self.responsible_id.id), ('vendor_id', '=', self.vendor_id.id) - ], order='product_price asc', limit=1) + ], order='count_trx_po desc, count_trx_po_vendor desc', limit=1) else: - purchase_price = self.env['purchase.pricelist'].search([('product_id', '=', point.product_id.id)], order='product_price asc', limit=1) + purchase_price = self.env['purchase.pricelist'].search([ + ('product_id', '=', point.product_id.id), + # ('product_id.x_manufacture.user_id.id', '=', self.responsible_id.id), + ], order='count_trx_po desc, count_trx_po_vendor desc', limit=1) vendor_id = purchase_price.vendor_id.id - price = purchase_price.product_price or 0 + price = self._get_valid_purchase_price(purchase_price) + + if self.vendor_id and self.vendor_id.id != vendor_id: + continue self.env['automatic.purchase.line'].create([{ 'automatic_purchase_id': self.id, @@ -128,6 +138,19 @@ class AutomaticPurchase(models.Model): _logger.info('Create Automatic Purchase Line %s' % point.product_id.name) self.notification = "Automatic PO Created %s Lines" % count + def _get_valid_purchase_price(self, purchase_price): + p_price = 0 + if purchase_price.system_price > 0 and purchase_price.product_price > 0: + if purchase_price.human_last_update > purchase_price.system_last_update: + p_price = purchase_price.product_price + else: + p_price = purchase_price.system_price + elif purchase_price.system_price > 0 and purchase_price.product_price == 0: + p_price = purchase_price.system_price + elif purchase_price.system_price == 0 and purchase_price.product_price > 0: + p_price = purchase_price.product_price + return p_price + class AutomaticPurchaseLine(models.Model): _name = 'automatic.purchase.line' diff --git a/indoteknik_custom/models/commision.py b/indoteknik_custom/models/commision.py new file mode 100644 index 00000000..d4942a0d --- /dev/null +++ b/indoteknik_custom/models/commision.py @@ -0,0 +1,275 @@ +from odoo import models, api, fields +from odoo.exceptions import UserError +from datetime import datetime +import logging + +_logger = logging.getLogger(__name__) + + +class CustomerRebate(models.Model): + _name = 'customer.rebate' + _order = 'id desc' + _inherit = ['mail.thread'] + + partner_id = fields.Many2one('res.partner', string='Customer', required=True) + date_from = fields.Date(string='Date From', required=True, help="Pastikan tanggal 1 januari, jika tidak, code akan break") + date_to = fields.Date(string='Date To', required=True, help="Pastikan tanggal 31 desember, jika tidak, code akan break") + description = fields.Char(string='Description') + target_1st = fields.Float(string='Target/Quarter 1st') + target_2nd = fields.Float(string='Target/Quarter 2nd') + achieve_1 = fields.Float(string='Achieve 1 %') + achieve_2 = fields.Float(string='Achieve 2 %') + dpp_q1 = fields.Float(string='DPP Q1', compute='_compute_current_dpp') + dpp_q2 = fields.Float(string='DPP Q2', compute='_compute_current_dpp') + dpp_q3 = fields.Float(string='DPP Q3', compute='_compute_current_dpp') + dpp_q4 = fields.Float(string='DPP Q4', compute='_compute_current_dpp') + status_q1 = fields.Char(string='Status Q1', compute='_compute_achievement') + status_q2 = fields.Char(string='Status Q2', compute='_compute_achievement') + status_q3 = fields.Char(string='Status Q3', compute='_compute_achievement') + status_q4 = fields.Char(string='Status Q4', compute='_compute_achievement') + + # all code class CustomerRebate deprecated, cause lack of performance + def _compute_current_dpp(self): + for line in self: + line.dpp_q1 = line._get_current_dpp_q1(line) + line.dpp_q2 = line._get_current_dpp_q2(line) + line.dpp_q3 = line._get_current_dpp_q3(line) + line.dpp_q4 = line._get_current_dpp_q4(line) + + def _compute_achievement(self): + for line in self: + line.status_q1 = line._check_achievement(line.target_1st, line.target_2nd, line.dpp_q1) + line.status_q2 = line._check_achievement(line.target_1st, line.target_2nd, line.dpp_q2) + line.status_q3 = line._check_achievement(line.target_1st, line.target_2nd, line.dpp_q3) + line.status_q4 = line._check_achievement(line.target_1st, line.target_2nd, line.dpp_q4) + + def _check_achievement(self, target_1st, target_2nd, dpp): + status = 'not achieve' + if dpp >= target_1st: + status = '1st' + elif dpp >= target_2nd: + status = '2nd' + else: + status = 'not achieve' + return status + + def _get_current_dpp_q1(self, line): + sum_dpp = 0 + brand = [10, 89, 122] + where = [ + ('move_id.move_type', '=', 'out_invoice'), + ('move_id.state', '=', 'posted'), + ('move_id.is_customer_commision', '=', False), + ('move_id.partner_id.id', '=', line.partner_id.id), + ('move_id.invoice_date', '>=', line.date_from), + ('move_id.invoice_date', '<=', '2023-03-31'), + ('product_id.x_manufacture', 'in', brand), + ] + invoice_lines = self.env['account.move.line'].search(where, order='id') + for invoice_line in invoice_lines: + sum_dpp += invoice_line.price_subtotal + return sum_dpp + + def _get_current_dpp_q2(self, line): + sum_dpp = 0 + brand = [10, 89, 122] + where = [ + ('move_id.move_type', '=', 'out_invoice'), + ('move_id.state', '=', 'posted'), + ('move_id.is_customer_commision', '=', False), + ('move_id.partner_id.id', '=', line.partner_id.id), + ('move_id.invoice_date', '>=', '2023-04-01'), + ('move_id.invoice_date', '<=', '2023-06-30'), + ('product_id.x_manufacture', 'in', brand), + ] + invoices = self.env['account.move.line'].search(where, order='id') + for invoice in invoices: + sum_dpp += invoice.price_subtotal + return sum_dpp + + def _get_current_dpp_q3(self, line): + sum_dpp = 0 + brand = [10, 89, 122] + where = [ + ('move_id.move_type', '=', 'out_invoice'), + ('move_id.state', '=', 'posted'), + ('move_id.is_customer_commision', '=', False), + ('move_id.partner_id.id', '=', line.partner_id.id), + ('move_id.invoice_date', '>=', '2023-07-01'), + ('move_id.invoice_date', '<=', '2023-09-30'), + ('product_id.x_manufacture', 'in', brand), + ] + invoices = self.env['account.move.line'].search(where, order='id') + for invoice in invoices: + sum_dpp += invoice.price_subtotal + return sum_dpp + + def _get_current_dpp_q4(self, line): + sum_dpp = 0 + brand = [10, 89, 122] + where = [ + ('move_id.move_type', '=', 'out_invoice'), + ('move_id.state', '=', 'posted'), + ('move_id.is_customer_commision', '=', False), + ('move_id.partner_id.id', '=', line.partner_id.id), + ('move_id.invoice_date', '>=', '2023-10-01'), + ('move_id.invoice_date', '<=', line.date_to), + ('product_id.x_manufacture', 'in', brand), + ] + invoices = self.env['account.move.line'].search(where, order='id') + for invoice in invoices: + sum_dpp += invoice.price_subtotal + return sum_dpp + + +class CustomerCommision(models.Model): + _name = 'customer.commision' + _order = 'id desc' + _inherit = ['mail.thread'] + _rec_name = 'number' + + number = fields.Char(string='Document No', index=True, copy=False, readonly=True) + date_from = fields.Date(string='Date From', required=True) + date_to = fields.Date(string='Date To', required=True) + partner_id = fields.Many2one('res.partner', String='Customer', required=True) + description = fields.Char(string='Description') + notification = fields.Char(string='Notification') + commision_lines = fields.One2many('customer.commision.line', 'customer_commision_id', string='Lines', auto_join=True) + status = fields.Selection([ + ('pengajuan1', 'Menunggu Approval Marketing'), + ('pengajuan2', 'Menunggu Approval Pimpinan'), + ('approved', 'Approved') + ], string='Status', copy=False, readonly=True, tracking=3) + commision_percent = fields.Float(string='Commision %', tracking=3) + commision_amt = fields.Float(string='Commision Amount', tracking=3) + total_dpp = fields.Float(string='Total DPP', compute='_compute_total_dpp') + commision_type = fields.Selection([ + ('fee', 'Fee'), + ('cashback', 'Cashback'), + ('rebate', 'Rebate'), + ], string='Commision Type', required=True) + + # add status for type of commision, fee, rebate / cashback + # include child or not? + + @api.constrains('commision_percent') + def _onchange_commision_percent(self): + print('masuk onchange commision percent') + self.commision_amt = self.commision_percent * self.total_dpp // 100 + + # @api.constrains('commision_amt') + # def _onchange_commision_amt(self): + # print('masuk onchange commision amt') + # self.commision_percent = (self.commision_amt / self.grand_total * 100) + + def _compute_total_dpp(self): + for data in self: + total_dpp = 0 + for line in data.commision_lines: + total_dpp = total_dpp + line.dpp + data.total_dpp = total_dpp + + @api.model + def create(self, vals): + vals['number'] = self.env['ir.sequence'].next_by_code('customer.commision') or '0' + result = super(CustomerCommision, self).create(vals) + return result + + def action_confirm_customer_commision(self):#add 2 step approval + if not self.status: + self.status = 'pengajuan1' + elif self.status == 'pengajuan1' and self.env.user.id == 19: + self.status = 'pengajuan2' + elif self.status == 'pengajuan2' and self.env.user.is_leader: + for line in self.commision_lines: + line.invoice_id.is_customer_commision = True + self.status = 'approved' + else: + raise UserError('Harus di approved oleh yang bersangkutan') + return + + def generate_customer_commision(self): + if self.commision_lines: + raise UserError('Line sudah ada, tidak bisa di generate ulang') + + if self.commision_type == 'fee': + self._generate_customer_commision_fee() + else: + self._generate_customer_commision_rebate() + + def _generate_customer_commision_rebate(self): + partners = [] + partners += self.partner_id.child_ids + partners.append(self.partner_id) + + for partner in partners: + brand = [92, 10, 89, 12, 324, 11] + where = [ + ('move_id.move_type', '=', 'out_invoice'), + ('move_id.state', '=', 'posted'), + ('move_id.is_customer_commision', '=', False), + ('move_id.amount_residual_signed', '=', 0), + ('move_id.partner_id.id', '=', partner.id), + ('move_id.invoice_date', '>=', self.date_from), + ('move_id.invoice_date', '<=', self.date_to), + ('product_id.x_manufacture', 'in', brand), + ] + invoice_lines = self.env['account.move.line'].search(where, order='id') + for invoice_line in invoice_lines: + tax = invoice_line.price_total - invoice_line.price_subtotal + self.env['customer.commision.line'].create([{ + 'customer_commision_id': self.id, + 'partner_id': invoice_line.move_id.partner_id.id, + 'invoice_id': invoice_line.move_id.id, + 'state': invoice_line.move_id.state, + 'product_id': invoice_line.product_id.id, + 'dpp': invoice_line.price_subtotal, + 'tax': tax, + 'total': invoice_line.price_total + }]) + return + + def _generate_customer_commision_fee(self): + partners = [] + partners += self.partner_id.child_ids + partners.append(self.partner_id) + + for partner in partners: + where = [ + ('move_type', '=', 'out_invoice'), + ('state', '=', 'posted'), + ('is_customer_commision', '=', False), + ('amount_residual_signed', '=', 0), + ('partner_id.id', '=', partner.id), + ('invoice_date', '>=', self.date_from), + ('invoice_date', '<=', self.date_to), + ] + invoices = self.env['account.move'].search(where, order='id') + for invoice in invoices: + self.env['customer.commision.line'].create([{ + 'customer_commision_id': self.id, + 'partner_id': invoice.partner_id.id, + 'invoice_id': invoice.id, + 'state': invoice.state, + 'dpp': invoice.amount_untaxed_signed, + 'tax': invoice.amount_tax_signed, + 'total': invoice.amount_total_signed + }]) + return + +class CustomerCommisionLine(models.Model): + _name = 'customer.commision.line' + _order = 'id' + + customer_commision_id = fields.Many2one('customer.commision', string='Ref', required=True, ondelete='cascade', copy=False) + invoice_id = fields.Many2one('account.move', string='Invoice') + partner_id = fields.Many2one('res.partner', string='Customer') + state = fields.Char(string='InvStatus') + dpp = fields.Float(string='DPP') + tax = fields.Float(string='TaxAmt') + total = fields.Float(string='Total') + product_id = fields.Many2one('product.product', string='Product') + +class AccountMove(models.Model): + _inherit = 'account.move' + is_customer_commision = fields.Boolean(string='Customer Commision Used') diff --git a/indoteknik_custom/models/product_monitoring.py b/indoteknik_custom/models/product_monitoring.py new file mode 100644 index 00000000..df9701ab --- /dev/null +++ b/indoteknik_custom/models/product_monitoring.py @@ -0,0 +1,35 @@ +from odoo import models, fields, tools, api + +class ProductMonitoring(models.Model): + _name = 'product.monitoring' + _auto = False + _rec_name = 'product_id' + + id = fields.Integer() + product_id = fields.Many2one('product.product', string='Product') + outgoing_qty = fields.Float(string="Outgoing", related='product_id.outgoing_qty') + incoming_qty = fields.Float(string="Incoming", related='product_id.incoming_qty') + qty_available = fields.Float(string="On Hand", related='product_id.qty_available') + qty_upcoming = fields.Float(string="Upcoming", related='product_id.qty_upcoming') + status_stock = fields.Selection([ + ('outgoing_gt_stock', 'Outgoing > Stock'), + ('outgoing_lt_stock', 'Outgoing < Stock'), + ], string="Status Stock", compute='_compute_status_stock') + + def _compute_status_stock(self): + for product in self: + product.status_stock = 'outgoing_lt_stock' if product.outgoing_qty <= product.qty_upcoming else 'outgoing_gt_stock' + + def init(self): + tools.drop_view_if_exists(self.env.cr, self._table) + self.env.cr.execute(""" + CREATE OR REPLACE VIEW %s AS ( + SELECT + sm.product_id AS id, + sm.product_id AS product_id + FROM stock_move sm + LEFT JOIN stock_picking sp ON sm.picking_id = sp.id + WHERE sp.state NOT IN ('cancel', 'done') AND sm.product_id IS NOT null + GROUP BY sm.product_id + ) + """ % self._table)
\ No newline at end of file diff --git a/indoteknik_custom/models/product_template.py b/indoteknik_custom/models/product_template.py index defcbdd4..d1de2221 100755 --- a/indoteknik_custom/models/product_template.py +++ b/indoteknik_custom/models/product_template.py @@ -52,7 +52,15 @@ class ProductTemplate(models.Model): help='Centang jika ingin ditammpilkan di website sebagai segment Produk Baru') seq_new_product = fields.Integer(string='Seq New Product', help='Urutan Sequence New Product') is_edited = fields.Boolean(string='Is Edited') - + qty_sold = fields.Float(string='Sold Quantity', compute='_get_qty_sold') + kind_of = fields.Selection([ + ('sp', 'Spare Part'), + ('acc', 'Accessories') + ], string='Kind of', copy=False) + + def _get_qty_sold(self): + for rec in self: + rec.qty_sold = sum(x.qty_sold for x in rec.product_variant_ids) def day_product_to_edit(self): day_products = [] @@ -184,12 +192,7 @@ class ProductTemplate(models.Model): def _compute_web_price(self): for template in self: - products = self.env['product.product'].search([ - ('product_tmpl_id', '=', template.id), - ('active', 'in', [True, False]) - ]) - for variants in products: - template.web_price = variants[0].web_price + template.web_price = template.product_variant_id.web_price def _have_promotion_program(self): for template in self: @@ -308,6 +311,12 @@ class ProductTemplate(models.Model): } self.env['token.storage'].create([values]) return values + + def write(self, vals): + if self.id == 224484: + raise UserError('Tidak dapat mengubah produk sementara') + + return super(ProductTemplate, self).write(vals) class ProductProduct(models.Model): _inherit = "product.product" @@ -329,8 +338,22 @@ class ProductProduct(models.Model): material = fields.Char(string='Material') qty_onhand_bandengan = fields.Float(string='Qty Incoming Bandengan', compute='_get_qty_onhand_bandengan') qty_incoming_bandengan = fields.Float(string='Qty Incoming Bandengan', compute='_get_qty_incoming_bandengan') + qty_upcoming = fields.Float(string='Qty Upcoming', compute='_get_qty_upcoming') sla_version = fields.Integer(string="SLA Version", default=0) is_edited = fields.Boolean(string='Is Edited') + qty_sold = fields.Float(string='Sold Quantity', compute='_get_qty_sold') + + def _get_qty_upcoming(self): + for product in self: + product.qty_upcoming = product.incoming_qty + product.qty_available + + def _get_qty_sold(self): + for product in self: + order_line = self.env['sale.order.line'].search([ + ('order_id.state', 'in', ['done', 'sale']), + ('product_id', '=', product.id) + ]) + product.qty_sold = sum(x.product_uom_qty for x in order_line) def day_product_to_edit(self): day_products = [] @@ -401,9 +424,9 @@ class ProductProduct(models.Model): def _compute_web_price(self): for product in self: - pricelist_id = self.env.context.get('pricelist') + pricelist_id = self.env['ir.config_parameter'].sudo().get_param('product.pricelist.default_price_id_v2') - domain = [('pricelist_id', '=', pricelist_id or 1), ('product_id', '=', product.id)] + domain = [('pricelist_id.id', '=', pricelist_id or 17022), ('product_id.id', '=', product.id)] product_pricelist_item = self.env['product.pricelist.item'].search(domain, limit=1) if product_pricelist_item.base_pricelist_id: diff --git a/indoteknik_custom/models/purchase_order.py b/indoteknik_custom/models/purchase_order.py index 8ad25228..b0f1a569 100755 --- a/indoteknik_custom/models/purchase_order.py +++ b/indoteknik_custom/models/purchase_order.py @@ -47,6 +47,17 @@ class PurchaseOrder(models.Model): count_line_product = fields.Float('Total Item', compute='compute_count_line_product') note_description = fields.Char(string='Note', help='bisa diisi sebagai informasi indent barang tertentu atau apapun') has_active_invoice = fields.Boolean(string='Has Active Invoice', compute='_compute_has_active_invoice') + description = fields.Char(string='Description', help='bisa diisi sebagai informasi indent barang tertentu atau apapun') + purchase_order_lines = fields.One2many('purchase.order.line', 'order_id', string='Indent', auto_join=True) + responsible_ids = fields.Many2many('res.users', string='Responsibles', compute='_compute_responsibles') + + def _compute_responsibles(self): + for purchase in self: + resposible_ids = [] + for line in purchase.order_line: + resposible_ids.append(line.product_id.x_manufacture.user_id.id) + resposible_ids = list(set(resposible_ids)) + purchase.responsible_ids = resposible_ids def _compute_has_active_invoice(self): for order in self: @@ -55,6 +66,14 @@ class PurchaseOrder(models.Model): def add_product_to_pricelist(self): for line in self.order_line: current_time = datetime.utcnow() + price_unit = line.price_unit + taxes = line.taxes_id + for tax in taxes: + tax_include = tax.price_include + tax_amt = tax.amount + if taxes: + if not tax_include: + price_unit = price_unit + (price_unit * tax_amt / 100) purchase_pricelist = self.env['purchase.pricelist'].search([ ('product_id', '=', line.product_id.id), @@ -66,7 +85,7 @@ class PurchaseOrder(models.Model): 'vendor_id': line.order_id.partner_id.id, 'product_id': line.product_id.id, 'product_price': 0.00, - 'system_price': line.price_unit, + 'system_price': price_unit, 'system_last_update': current_time, }]) return True @@ -74,7 +93,7 @@ class PurchaseOrder(models.Model): for pricelist in purchase_pricelist: pricelist.write({ 'system_last_update': current_time, - 'system_price': line.price_unit + 'system_price': price_unit }) def _compute_date_planned(self): @@ -329,12 +348,11 @@ class PurchaseOrder(models.Model): def re_calculate(self): for line in self.order_line: sale_order_line = self.env['sale.order.line'].search([ - ('id', '=', line.so_line_id.id), + ('product_id', 'in', [line.product_id.id]), ('order_id', '=', line.order_id.sale_order_id.id) - ], limit=1, order='price_reduce_taxexcl') + ]) for so_line in sale_order_line: - unit_price = line.price_unit - so_line.purchase_price = unit_price + so_line.purchase_price = line.price_unit def button_cancel(self): res = super(PurchaseOrder, self).button_cancel() diff --git a/indoteknik_custom/models/purchase_order_line.py b/indoteknik_custom/models/purchase_order_line.py index 95e85122..2e91bb69 100755 --- a/indoteknik_custom/models/purchase_order_line.py +++ b/indoteknik_custom/models/purchase_order_line.py @@ -30,6 +30,7 @@ class PurchaseOrderLine(models.Model): suggest = fields.Char(string='Suggest') price_vendor = fields.Float(string='Price Vendor', compute='compute_price_vendor') so_line_id = fields.Many2one('sale.order.line', string='ID SO Line') + indent = fields.Boolean(string='Indent', help='centang ini jika barang indent') def compute_price_vendor(self): for line in self: diff --git a/indoteknik_custom/models/purchase_pricelist.py b/indoteknik_custom/models/purchase_pricelist.py index 3607defe..b7c3785a 100755 --- a/indoteknik_custom/models/purchase_pricelist.py +++ b/indoteknik_custom/models/purchase_pricelist.py @@ -14,6 +14,8 @@ class PurchasePricelist(models.Model): system_price = fields.Float(string='System Price', required=True) human_last_update = fields.Datetime(string='Human Update') system_last_update = fields.Datetime(string='System Update') + count_trx_po = fields.Integer(string='Count Trx Product') + count_trx_po_vendor = fields.Integer(string='Count Trx Vendor') @api.depends('product_id', 'vendor_id') def _compute_name(self): diff --git a/indoteknik_custom/models/requisition.py b/indoteknik_custom/models/requisition.py index 19f0ba7e..6408c4fd 100644 --- a/indoteknik_custom/models/requisition.py +++ b/indoteknik_custom/models/requisition.py @@ -9,6 +9,8 @@ _logger = logging.getLogger(__name__) class Requisition(models.Model): _name = 'requisition' _order = 'id desc' + _inherit = ['mail.thread'] + _rec_name = 'number' number = fields.Char(string='Document No', index=True, copy=False, readonly=True) date_doc = fields.Date(string='Date', help='isi tanggal hari ini') @@ -26,108 +28,108 @@ class Requisition(models.Model): result = super(Requisition, self).create(vals) return result - def create_requisition_from_sales_with_price(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') - - 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 = order_line.purchase_price - vendor_id = order_line.vendor_id.id - - # get qty available bandengan - qty_available = order_line.product_id.qty_onhand_bandengan + order_line.product_id.qty_incoming_bandengan - order_line.product_id.outgoing_qty - suggest = 'harus beli' - if qty_available > order_line.product_qty: - suggest = 'masih cukup' - - 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': 'sales', - 'qty_available_store': qty_available, - 'suggest': suggest, - }]) - count+=1 - _logger.info('Create Requisition %s' % order_line.product_id.name) - self.notification = "Requisition Created %s lines" % count - - 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') + # def create_requisition_from_sales_with_price(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') + + # 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 = order_line.purchase_price + # vendor_id = order_line.vendor_id.id + + # # get qty available bandengan + # qty_available = order_line.product_id.qty_onhand_bandengan + order_line.product_id.qty_incoming_bandengan - order_line.product_id.outgoing_qty + # suggest = 'harus beli' + # if qty_available > order_line.product_qty: + # suggest = 'masih cukup' + + # 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': 'sales', + # 'qty_available_store': qty_available, + # 'suggest': suggest, + # }]) + # count+=1 + # _logger.info('Create Requisition %s' % order_line.product_id.name) + # self.notification = "Requisition Created %s lines" % count + + # 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 - - # get qty available bandengan - qty_available = order_line.product_id.qty_onhand_bandengan + order_line.product_id.qty_incoming_bandengan - order_line.product_id.outgoing_qty - suggest = 'harus beli' - if qty_available > order_line.product_qty: - suggest = 'masih cukup' - - 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' + # # 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 + + # # get qty available bandengan + # qty_available = order_line.product_id.qty_onhand_bandengan + order_line.product_id.qty_incoming_bandengan - order_line.product_id.outgoing_qty + # suggest = 'harus beli' + # if qty_available > order_line.product_qty: + # suggest = 'masih cukup' + + # 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: + # 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: + # 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, - 'qty_available_store': qty_available, - 'suggest': suggest, - }]) - count+=1 - _logger.info('Create Requisition %s' % order_line.product_id.name) - self.notification = "Requisition Created %s lines" % count + # 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, + # 'qty_available_store': qty_available, + # 'suggest': suggest, + # }]) + # 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: @@ -141,13 +143,14 @@ class Requisition(models.Model): for vendor in vendor_ids: param_header = { 'partner_id': vendor['partner_id'][0], - 'partner_ref': self.sale_order_id.name, + # '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 + 'sale_order_id': self.sale_order_id.id, + 'note_description': 'from Purchase Requisition' } # new_po = self.env['purchase.order'].create([param_header]) products_vendors = self.env['requisition.line'].search([ @@ -156,9 +159,9 @@ class Requisition(models.Model): ('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): + if count == 200 or brand_id != product.brand_id.id: count = 0 counter_po_number += 1 new_po = self.env['purchase.order'].create([param_header]) @@ -178,14 +181,16 @@ class Requisition(models.Model): if qty_available > product.qty_purchase: suggest = 'masih cukup' + tax = [22] + 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, + 'price_unit': product.price_unit, + 'taxes_id': tax, 'qty_available_store': qty_available, 'suggest': suggest, } @@ -193,7 +198,7 @@ class Requisition(models.Model): 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.notification = self.notification + ' %s' % new_po.name self.is_po = True class RequisitionLine(models.Model): @@ -221,7 +226,13 @@ class RequisitionLine(models.Model): @api.onchange('price_unit') def _onchange_price_unit(self): - self.subtotal = self.price_unit * self.qty_purchase + for line in self: + line.subtotal = line.price_unit * line.qty_purchase + + @api.onchange('product_id') + def _onchange_product(self): + for line in self: + line.brand_id = line.product_id.product_tmpl_id.x_manufacture.id class RequisitionPurchaseMatch(models.Model): _name = 'requisition.purchase.match' diff --git a/indoteknik_custom/models/res_partner.py b/indoteknik_custom/models/res_partner.py index bc2a24b1..a1b57147 100644 --- a/indoteknik_custom/models/res_partner.py +++ b/indoteknik_custom/models/res_partner.py @@ -19,6 +19,8 @@ class ResPartner(models.Model): ]) sppkp = fields.Char(string="SPPKP") counter = fields.Integer(string="Counter", default=0) + digital_invoice_tax = fields.Boolean(string="Digital Invoice & Faktur Pajak") + is_potential = fields.Boolean(string='Potential') def get_child_ids(self): partner = self.env['res.partner'].search([('id', '=', self.id)], limit=1) diff --git a/indoteknik_custom/models/sale_monitoring.py b/indoteknik_custom/models/sale_monitoring.py index ad15e0c2..107d5296 100755 --- a/indoteknik_custom/models/sale_monitoring.py +++ b/indoteknik_custom/models/sale_monitoring.py @@ -21,12 +21,42 @@ class SaleMonitoring(models.Model): status = fields.Char(string="Status") po_number = fields.Char(string="PO Number") qty_reserved = fields.Integer(string="Qty Reserved") - note = fields.Char(string="Note", compute='compute_note') + note_so_line = fields.Selection([ + ('eta', 'ETA'), + ('info_sales', 'Info Sales'), + ('info_vendor', 'Info Vendor'), + ('penggabungan', 'Penggabungan'), + ], string="Note", compute='compute_note') + note = fields.Char(string="Note Detail", compute='compute_note_detail') + purchase_representative_id = fields.Many2one('res.users', string="Purchase Representative", readonly=True, compute='compute_purchase_representative') + + def compute_purchase_representative(self): + for sale in self: + po = self.env['purchase.order'].search([ + ('sale_order_id', '=', sale.sale_order_id.id), + ('user_id', '!=', False) + ]) + + user_id = False + + if po: + user_id = po[0].user_id + + sale.purchase_representative_id = user_id def compute_note(self): for sale in self: lines = self.env['sale.order.line'].search([ ('order_id', '=', sale.sale_order_id.id), + ('note', '!=', False) + ], limit=1) + + sale.note_so_line = lines.note + + def compute_note_detail(self): + for sale in self: + lines = self.env['sale.order.line'].search([ + ('order_id', '=', sale.sale_order_id.id), ('note_procurement', '!=', False) ]) @@ -51,12 +81,12 @@ class SaleMonitoring(models.Model): SUM(smd.qty_so_invoiced) AS qty_so_invoiced, sum(smd.qty_reserved) as qty_reserved, CASE - 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' + when sum(qty_so_invoiced) = sum(qty_so) then 'Invoiced' 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 dc4caa14..43b0b063 100755 --- a/indoteknik_custom/models/sale_monitoring_detail.py +++ b/indoteknik_custom/models/sale_monitoring_detail.py @@ -31,12 +31,12 @@ class SaleMonitoringDetail(models.Model): SELECT *, CASE - 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' + when qty_so_invoiced = qty_so then 'Invoiced' END AS status FROM ( diff --git a/indoteknik_custom/models/sale_order.py b/indoteknik_custom/models/sale_order.py index 9324930e..f9229bca 100755 --- a/indoteknik_custom/models/sale_order.py +++ b/indoteknik_custom/models/sale_order.py @@ -1,5 +1,6 @@ from odoo import fields, models, api, _ from odoo.exceptions import UserError +from datetime import datetime import logging, random, string, requests, math, json, re _logger = logging.getLogger(__name__) @@ -69,18 +70,28 @@ class SaleOrder(models.Model): customer_type = fields.Selection([ ('pkp', 'PKP'), ('nonpkp', 'Non PKP') - ]) - sppkp = fields.Char(string="SPPKP") - npwp = fields.Char(string="NPWP") + ], required=True) + sppkp = fields.Char(string="SPPKP", required=True) + npwp = fields.Char(string="NPWP", required=True) purchase_total = fields.Monetary(string='Purchase Total', compute='_compute_purchase_total') 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') - source_id = fields.Many2one('utm.source', 'Source', domain="[('id', 'in', [32, 59, 60, 61])]") + 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') picking_iu_id = fields.Many2one('stock.picking', 'Picking IU') helper_by_id = fields.Many2one('res.users', 'Helper By') + # picking_ids = fields.Many2many('stock.picking', string='Pickings', compute='_get_pickings', readonly=True, copy=False, search="_search_picking_ids") + + # def _get_pickings(self): + # state = ['assigned'] + # for order in self: + # pickings = self.env['stock.picking'].search([ + # ('sale_id.id', '=', order.id), + # ('state', 'in', state) + # ]) + # order.picking_ids = pickings @api.model def action_multi_update_state(self): @@ -193,8 +204,39 @@ class SaleOrder(models.Model): sale.so_status = 'sebagian' else: sale.so_status = 'menunggu' + + for picking in sale.picking_ids: + sum_qty_pick = sum(move_line.product_uom_qty for move_line in picking.move_ids_without_package) + sum_qty_reserved = sum(move_line.product_uom_qty for move_line in picking.move_line_ids_without_package) + if picking.state == 'done': + continue + elif sum_qty_pick == sum_qty_reserved and not picking.date_reserved:# baru ke reserved + current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + picking.date_reserved = current_time + elif sum_qty_pick == sum_qty_reserved:# sudah ada data reserved + picking.date_reserved = picking.date_reserved + else: + picking.date_reserved = '' + _logger.info('Calculate SO Status %s' % sale.id) + # def _search_picking_ids(self, operator, value): + # if operator == 'in' and value: + # self.env.cr.execute(""" + # SELECT array_agg(so.sale_id) + # FROM stock_picking so + # WHERE + # so.sale_id is not null and so.id = ANY(%s) + # """, (list(value),)) + # so_ids = self.env.cr.fetchone()[0] or [] + # return [('id', 'in', so_ids)] + # elif operator == '=' and not value: + # order_ids = self._search([ + # ('order_line.invoice_lines.move_id.move_type', 'in', ('out_invoice', 'out_refund')) + # ]) + # return [('id', 'not in', order_ids)] + # return ['&', ('order_line.invoice_lines.move_id.move_type', 'in', ('out_invoice', 'out_refund')), ('order_line.invoice_lines.move_id', operator, value)] + @api.onchange('partner_shipping_id') def onchange_partner_shipping(self): self.real_shipping_id = self.partner_shipping_id diff --git a/indoteknik_custom/models/sale_order_line.py b/indoteknik_custom/models/sale_order_line.py index 69328325..eda003c7 100644 --- a/indoteknik_custom/models/sale_order_line.py +++ b/indoteknik_custom/models/sale_order_line.py @@ -18,7 +18,13 @@ class SaleOrderLine(models.Model): delivery_amt_line = fields.Float('DeliveryAmtLine', compute='compute_delivery_amt_line') fee_third_party_line = fields.Float('FeeThirdPartyLine', compute='compute_fee_third_party_line', default=0) line_no = fields.Integer('No', default=0, copy=False) - note_procurement = fields.Char(string='Note', help="Harap diisi jika ada keterangan tambahan dari Procurement, agar dapat dimonitoring") + note = fields.Selection([ + ('eta', 'ETA'), + ('info_sales', 'Info Sales'), + ('info_vendor', 'Info Vendor'), + ('penggabungan', 'Penggabungan'), + ], string='Note', help="Harap diisi jika ada keterangan tambahan dari Procurement, agar dapat dimonitoring") + note_procurement = fields.Char(string='Note Detail', help="Harap diisi jika ada keterangan tambahan dari Procurement, agar dapat dimonitoring") vendor_subtotal = fields.Float(string='Vendor Subtotal', compute="_compute_vendor_subtotal") amount_voucher_disc = fields.Float(string='Voucher Discount') @@ -66,21 +72,37 @@ class SaleOrderLine(models.Model): cost = self.product_id.standard_price self.purchase_price = cost else: + # purchase_price = self.env['purchase.pricelist'].search( + # [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', self.product_id.id)], limit=1) purchase_price = self.env['purchase.pricelist'].search( - [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', self.product_id.id)], limit=1) - self.purchase_price = purchase_price.product_price + [('vendor_id', '=', self.vendor_id.id), ('product_id', '=', self.product_id.id)], + limit=1, order='count_trx_po desc, count_trx_po_vendor desc') + self.purchase_price = self._get_valid_purchase_price(purchase_price) self.purchase_tax_id = 22 + def _get_valid_purchase_price(self, purchase_price): + p_price = 0 + if purchase_price.system_price > 0 and purchase_price.product_price > 0: + if purchase_price.human_last_update > purchase_price.system_last_update: + p_price = purchase_price.product_price + else: + p_price = purchase_price.system_price + elif purchase_price.system_price > 0 and purchase_price.product_price == 0: + p_price = purchase_price.system_price + elif purchase_price.system_price == 0 and purchase_price.product_price > 0: + p_price = purchase_price.product_price + return p_price + @api.onchange('product_id') def product_id_change(self): super(SaleOrderLine, self).product_id_change() for line in self: if line.product_id and line.product_id.type == 'product': purchase_price = self.env['purchase.pricelist'].search( - [('product_id', '=', self.product_id.id)], limit=1, order='product_price ASC') + [('product_id', '=', self.product_id.id)], limit=1, order='count_trx_po desc, count_trx_po_vendor desc') line.vendor_id = purchase_price.vendor_id line.tax_id = line.order_id.sales_tax_id - line.purchase_price = purchase_price.product_price + line.purchase_price = self._get_valid_purchase_price(purchase_price) def compute_delivery_amt_line(self): for line in self: diff --git a/indoteknik_custom/models/solr/apache_solr_queue.py b/indoteknik_custom/models/solr/apache_solr_queue.py index 8dd7c273..07274295 100644 --- a/indoteknik_custom/models/solr/apache_solr_queue.py +++ b/indoteknik_custom/models/solr/apache_solr_queue.py @@ -72,11 +72,12 @@ class ApacheSolrQueue(models.Model): if count == 0: self.create(payload) - def delete_weekly_solr(self, limit=500): + def delete_weekly_solr(self, limit=500, days_after=30): solr = self.search([ ('execute_status', '=', 'success'), - ('execute_date', '>=', (datetime.utcnow() - timedelta(days=7))), + ('execute_date', '>=', (datetime.utcnow() - timedelta(days=days_after))), ], limit=limit) + for rec in solr: rec.unlink() diff --git a/indoteknik_custom/models/solr/product_product.py b/indoteknik_custom/models/solr/product_product.py index 31a0026d..03eaaf13 100644 --- a/indoteknik_custom/models/solr/product_product.py +++ b/indoteknik_custom/models/solr/product_product.py @@ -1,10 +1,11 @@ -from odoo import models, fields +from odoo import models, fields, api from datetime import datetime class ProductProduct(models.Model): _inherit = 'product.product' + unpublished = fields.Boolean(string='Unpublished') last_update_solr = fields.Datetime(string='Last Update Solr') desc_update_solr = fields.Char(string='Desc Update Solr') @@ -24,6 +25,7 @@ class ProductProduct(models.Model): def variant_solr_flag_to_solr(self, limit=500): variant_products = self.search([('solr_flag', '=', 2)], limit=limit) for product in variant_products: + product.product_tmpl_id._create_solr_queue('_sync_product_template_to_solr') product.product_tmpl_id._create_solr_queue('_sync_price_to_solr') product.solr_flag = 1 @@ -63,7 +65,8 @@ class ProductProduct(models.Model): 'search_rank_weekly_i': variant.product_tmpl_id.search_rank_weekly, 'attributes': [x.name for x in variant.product_template_attribute_value_ids], 'has_product_info_b': True, - 'publish_b': variant.product_tmpl_id.active and variant.product_tmpl_id.type == 'product', + 'publish_b': not variant.unpublished, + 'qty_sold_f': variant.qty_sold }) self.solr().add(docs=[document], softCommit=True) @@ -74,24 +77,12 @@ class ProductProduct(models.Model): def _sync_price_to_solr(self): solr_model = self.env['apache.solr'] + TIER_NUMBERS = ['1_v2', '2_v2', '3_v2', '4_v2', '5_v2'] for variant in self: - price_excl_after_disc = price_excl = discount = tax = 0 - flashsale_data = {} - - 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() - tax = variant._get_website_tax() - discount = variant._get_website_disc(0) - flashsale_data = variant.with_context(price_for="web")._get_flashsale_price() + flashsale_data = variant.with_context(price_for="web")._get_flashsale_price() - price_excl_v2 = variant._v2_get_website_price_exclude_tax() - price_excl_after_disc_v2 = variant._v2_get_website_price_after_disc_and_tax() - tax_v2 = variant._v2_get_website_tax() - - document = solr_model.get_doc('variants', variant.id) - document.update({ + flashsale_doc = { "id": variant.id, "flashsale_id_i": flashsale_data.get('flashsale_id', 0), "flashsale_tag_s": flashsale_data.get('flashsale_tag', ''), @@ -101,25 +92,19 @@ class ProductProduct(models.Model): "flashsale_base_price_f": flashsale_data.get('flashsale_base_price', 0), "flashsale_discount_f": flashsale_data.get('flashsale_discount', 0), "flashsale_price_f": flashsale_data.get('flashsale_price', 0), - "price_f": price_excl, - "discount_f": discount, - "price_discount_f": price_excl_after_disc, - "tax_f": tax, - "price_v2_f": price_excl_v2, - "price_discount_v2_f": price_excl_after_disc_v2, - "tax_v2_f": tax_v2, - }) - - for tier_number in [1, 2, 3, '1_v2', '2_v2', '3_v2', '4_v2', '5_v2']: + } + + price_doc = {} + + for tier_number in TIER_NUMBERS: tier = variant._get_pricelist_tier(tier_number) - document.update({ - f"discount_tier{tier_number}_f": tier.get(f'discount_tier{tier_number}', 0), - f"price_tier{tier_number}_f": tier.get(f'price_tier{tier_number}', 0), - }) - - # for tier_number in [1, 2, 3, '1_v2', '2_v2', '3_v2', '4_v2', '5_v2']: - # tier = tier_data[tier_number] + price_doc[f"discount_tier{tier_number}_f"] = tier.get(f'discount_tier{tier_number}', 0) + price_doc[f"price_tier{tier_number}_f"] = tier.get(f'price_tier{tier_number}', 0) + document = solr_model.get_doc('variants', variant.id) + document['id'] = variant.id + document.update(flashsale_doc) + document.update(price_doc) document.update({"has_price_info_b": True}) self.solr().add(docs=[document], softCommit=True) @@ -185,4 +170,13 @@ class ProductProduct(models.Model): results.append(result) - return results
\ No newline at end of file + return results + + @api.constrains('unpublished') + def _constrains_unpublished(self): + for rec in self: + if rec.product_variant_count == 1: + rec.product_tmpl_id.unpublished = rec.unpublished + + rec.product_tmpl_id._create_solr_queue_sync_product_template() +
\ 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 d7439bcb..648a0625 100644 --- a/indoteknik_custom/models/solr/product_template.py +++ b/indoteknik_custom/models/solr/product_template.py @@ -5,6 +5,7 @@ from datetime import datetime class ProductTemplate(models.Model): _inherit = "product.template" + unpublished = fields.Boolean(string='Unpublished') last_update_solr = fields.Datetime(string='Last Update Solr') desc_update_solr = fields.Char(string='Desc Update Solr') @@ -23,7 +24,7 @@ class ProductTemplate(models.Model): 'function_name': function_name }) - @api.constrains('name', 'default_code', 'weight', 'x_manufacture', 'public_categ_ids', 'search_rank', 'search_rank_weekly', 'image_1920', 'active') + @api.constrains('name', 'default_code', 'weight', 'x_manufacture', 'public_categ_ids', 'search_rank', 'search_rank_weekly', 'image_1920', 'unpublished') def _create_solr_queue_sync_product_template(self): self._create_solr_queue('_sync_product_template_to_solr') @@ -35,6 +36,7 @@ class ProductTemplate(models.Model): def solr_flag_to_solr(self, limit=500): template_products = self.search([('solr_flag', '=', 2)], limit=limit) for product in template_products: + product._create_solr_queue('_sync_product_template_to_solr') product._create_solr_queue('_sync_price_to_solr') product.solr_flag = 1 @@ -80,7 +82,8 @@ class ProductTemplate(models.Model): "category_name": category_name, "description_t": template.website_description or '', 'has_product_info_b': True, - 'publish_b': template.active and template.type == 'product' + 'publish_b': not template.unpublished, + "qty_sold_f": template.qty_sold }) self.solr().add(docs=[document], softCommit=True) @@ -96,56 +99,52 @@ class ProductTemplate(models.Model): def _sync_price_to_solr(self): solr_model = self.env['apache.solr'] + TIER_NUMBERS = ['1_v2', '2_v2', '3_v2', '4_v2', '5_v2'] for template in self: - flashsale_data = {} - price_excl = price_excl_after_disc = discount = tax = 0 - tier_data = {} + cheapest_flashsale = {} for variant in template.product_variant_ids: variant_flashsale = variant.with_context(price_for="web")._get_flashsale_price() variant_flashsale_price = variant_flashsale.get('flashsale_price', 0) - flashsale_data_price = flashsale_data.get('flashsale_price', 0) - - if flashsale_data_price == 0 or (variant_flashsale_price != 0 and variant_flashsale_price < flashsale_data_price): - flashsale_data = variant_flashsale - - 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() - - price_excl_v2 = variant._v2_get_website_price_exclude_tax() - price_excl_after_disc_v2 = variant._v2_get_website_price_after_disc_and_tax() - tax_v2 = variant._v2_get_website_tax() - + cheapest_flashsale_price = cheapest_flashsale.get('flashsale_price', 0) + + if cheapest_flashsale_price == 0 or (variant_flashsale_price != 0 and variant_flashsale_price < cheapest_flashsale_price): + cheapest_flashsale = variant_flashsale + + flashsale_doc = { + "flashsale_id_i": cheapest_flashsale.get('flashsale_id', 0), + "flashsale_tag_s": cheapest_flashsale.get('flashsale_tag', ''), + "flashsale_name_s": cheapest_flashsale.get('flashsale_name', ''), + "flashsale_start_date_s": cheapest_flashsale.get('flashsale_start_date', ''), + "flashsale_end_date_s": cheapest_flashsale.get('flashsale_end_date', ''), + "flashsale_base_price_f": cheapest_flashsale.get('flashsale_base_price', 0), + "flashsale_discount_f": cheapest_flashsale.get('flashsale_discount', 0), + "flashsale_price_f": cheapest_flashsale.get('flashsale_price', 0) + } + + price_doc = {} + + # Loop tier to get each variant price + for tier_number in TIER_NUMBERS: + for variant in template.product_variant_ids: + tier = variant._get_pricelist_tier(tier_number) + discount_tier_key = f'discount_tier{tier_number}' + price_tier_key = f'price_tier{tier_number}' + + variant_discount = tier.get(discount_tier_key, 0) + variant_price = tier.get(price_tier_key, 0) + + price_tier = price_doc.get(f"{price_tier_key}_f", 0) + # When price tier is 0 or variant_price less than price tier then use variant price + if price_tier == 0 or (variant_price < price_tier and variant_price > 0): + price_doc[f"{discount_tier_key}_f"] = variant_discount + price_doc[f"{price_tier_key}_f"] = variant_price + document = solr_model.get_doc('product', template.id) - document.update({ - "id": template.id, - "flashsale_id_i": flashsale_data.get('flashsale_id', 0), - "flashsale_tag_s": flashsale_data.get('flashsale_tag', ''), - "flashsale_name_s": flashsale_data.get('flashsale_name', ''), - "flashsale_start_date_s": flashsale_data.get('flashsale_start_date', ''), - "flashsale_end_date_s": flashsale_data.get('flashsale_end_date', ''), - "flashsale_base_price_f": flashsale_data.get('flashsale_base_price', 0), - "flashsale_discount_f": flashsale_data.get('flashsale_discount', 0), - "flashsale_price_f": flashsale_data.get('flashsale_price', 0), - "price_f": price_excl, - "discount_f": discount, - "price_discount_f": price_excl_after_disc, - "tax_f": tax, - "price_v2_f": price_excl_v2, - "price_discount_v2_f": price_excl_after_disc_v2, - "tax_v2_f": tax_v2, - }) - - for tier_number in [1, 2, 3, '1_v2', '2_v2', '3_v2', '4_v2', '5_v2']: - tier = variant._get_pricelist_tier(tier_number) - document.update({ - f"discount_tier{tier_number}_f": tier.get(f'discount_tier{tier_number}', 0), - f"price_tier{tier_number}_f": tier.get(f'price_tier{tier_number}', 0), - }) - + document['id'] = template.id + document.update(flashsale_doc) + document.update(price_doc) document.update({"has_price_info_b": True}) self.solr().add(docs=[document], softCommit=True) @@ -220,3 +219,8 @@ class ProductTemplate(models.Model): results.append(result) return results + + @api.constrains('active') + def constrains_active(self): + for rec in self: + rec._create_solr_queue_sync_product_template()
\ No newline at end of file diff --git a/indoteknik_custom/models/solr/x_manufactures.py b/indoteknik_custom/models/solr/x_manufactures.py index 375b7708..98b1d01d 100644 --- a/indoteknik_custom/models/solr/x_manufactures.py +++ b/indoteknik_custom/models/solr/x_manufactures.py @@ -40,7 +40,7 @@ class XManufactures(models.Model): document.update({ 'id': brands.id, 'display_name_s': brands.display_name, - 'name_s': brands.x_name, + 'name_s': brands.x_name.lower(), 'sequence_i': brands.sequence or '', 'negara_asal_s': brands.x_negara_asal or '', 'short_desc_s': brands.x_short_desc or '', diff --git a/indoteknik_custom/models/stock_picking.py b/indoteknik_custom/models/stock_picking.py index 418649b1..a5e533b1 100644 --- a/indoteknik_custom/models/stock_picking.py +++ b/indoteknik_custom/models/stock_picking.py @@ -1,6 +1,7 @@ from odoo import fields, models, api, _ from odoo.exceptions import AccessError, UserError, ValidationError from odoo.tools.float_utils import float_is_zero +from datetime import datetime from itertools import groupby import pytz, datetime @@ -69,11 +70,12 @@ class StockPicking(models.Model): ('hold', 'Hold by Sales'), ('not_paid', 'Customer belum bayar'), ('partial', 'Kirim Parsial') - ], string='Note', help='jika field ini diisi maka tidak akan dihitung ke lead time') + ], string='Note Logistic', help='jika field ini diisi maka tidak akan dihitung ke lead time') waybill_id = fields.One2many(comodel_name='airway.bill', inverse_name='do_id', string='Airway Bill') purchase_representative_id = fields.Many2one('res.users', related='move_lines.purchase_line_id.order_id.user_id', string="Purchase Representative", readonly=True) carrier_id = fields.Many2one('delivery.carrier', string='Shipping Method') shipping_status = fields.Char(string='Shipping Status', compute="_compute_shipping_status") + date_reserved = fields.Datetime(string="Date Reserved", help='Tanggal ter-reserved semua barang nya') def _compute_shipping_status(self): for rec in self: @@ -309,6 +311,10 @@ class StockPicking(models.Model): if product: product.product_tmpl_id._create_solr_queue('_sync_product_stock_to_solr') + if not self.date_reserved: + current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + self.date_reserved = current_time + res = super(StockPicking, self).button_validate() self.calculate_line_no() return res diff --git a/indoteknik_custom/models/stock_warehouse_orderpoint.py b/indoteknik_custom/models/stock_warehouse_orderpoint.py new file mode 100644 index 00000000..277c8dc3 --- /dev/null +++ b/indoteknik_custom/models/stock_warehouse_orderpoint.py @@ -0,0 +1,10 @@ +from odoo import fields, models, api, _ + +class StockWarehouseOrderpoint(models.Model): + _inherit = 'stock.warehouse.orderpoint' + + responsible_id = fields.Many2one('res.users', string='Responsible', compute='_compute_responsible') + + def _compute_responsible(self): + for stock in self: + stock.responsible_id = stock.product_id.x_manufacture.user_id diff --git a/indoteknik_custom/models/users.py b/indoteknik_custom/models/users.py index b90c0097..2ff9933e 100644 --- a/indoteknik_custom/models/users.py +++ b/indoteknik_custom/models/users.py @@ -11,6 +11,7 @@ class Users(models.Model): is_accounting = fields.Boolean(string='Accounting', help='Berhak Approval Internal Use') is_logistic_approver = fields.Boolean(string='Logistic Approver', help='Berhak Approval Penerimaan Barang') is_editor_product = fields.Boolean(string='Editor Product', help='Berhak Mengedit Data Product') + is_admin_reconcile = fields.Boolean(string='Admin Reconcile', help='Berhak Mengedit Journal Reconcile') def notify_internal_users(self, message, title): users = self.search([('share', '=', False)]) diff --git a/indoteknik_custom/models/voucher.py b/indoteknik_custom/models/voucher.py index a40f8c42..66c50c24 100644 --- a/indoteknik_custom/models/voucher.py +++ b/indoteknik_custom/models/voucher.py @@ -12,7 +12,7 @@ class Voucher(models.Model): image = fields.Binary(string='Image') code = fields.Char(string='Code', help='Kode voucher yang akan berlaku untuk pengguna') description = fields.Text(string='Description') - discount_amount = fields.Integer(string='Discount Amount') + discount_amount = fields.Float(string='Discount Amount') discount_type = fields.Selection(string='Discount Type', selection=[ ('percentage', 'Percentage'), diff --git a/indoteknik_custom/models/voucher_line.py b/indoteknik_custom/models/voucher_line.py index 8b449d1f..890471dc 100644 --- a/indoteknik_custom/models/voucher_line.py +++ b/indoteknik_custom/models/voucher_line.py @@ -7,7 +7,7 @@ class Voucher(models.Model): voucher_id = fields.Many2one('voucher', string='Voucher') manufacture_id = fields.Many2one('x_manufactures', string='Brand') min_purchase_amount = fields.Integer(string='Min. Purchase Amount', help='Nominal minimum untuk dapat menggunakan voucher. Isi 0 jika tidak ada minimum purchase amount') - discount_amount = fields.Integer(string='Discount Amount') + discount_amount = fields.Float(string='Discount Amount') discount_type = fields.Selection(string='Discount Type', selection=[ ('percentage', 'Percentage'), diff --git a/indoteknik_custom/models/website_user_cart.py b/indoteknik_custom/models/website_user_cart.py index 47a695fe..bbc14c88 100644 --- a/indoteknik_custom/models/website_user_cart.py +++ b/indoteknik_custom/models/website_user_cart.py @@ -55,11 +55,15 @@ class WebsiteUserCart(models.Model): def get_product_by_user(self, user_id, selected=False, source=False): user_id = int(user_id) - source = source if source else 'add_to_cart' + + if source == 'buy': + source = ['buy'] + else: + source = ['add_to_cart', 'buy'] parameters = [ ('user_id', '=', user_id), - ('source', '=', source) + ('source', 'in', source) ] if selected: @@ -91,6 +95,7 @@ class WebsiteUserCart(models.Model): tax = round(subtotal * 0.11) grand_total = subtotal + tax total_weight = sum(x['weight'] * x['quantity'] for x in products) + total_weight = round(total_weight, 2) result = { 'total_purchase': total_purchase, 'total_discount': total_discount, diff --git a/indoteknik_custom/models/x_manufactures.py b/indoteknik_custom/models/x_manufactures.py index e48a5367..abedf0cf 100755 --- a/indoteknik_custom/models/x_manufactures.py +++ b/indoteknik_custom/models/x_manufactures.py @@ -47,6 +47,8 @@ class XManufactures(models.Model): parent_id = fields.Many2one('x_manufactures', string='Parent', help='Parent Brand tersebut') category_ids = fields.Many2many('product.public.category', string='Category', help='Brand tsb memiliki Category apa saja') vendor_ids = fields.Many2many('res.partner', string='Vendor', compute='_compute_vendor_ids') + # user_id = fields.Many2one('res.users', string='Responsible', domain="['|'('id', '=', 19), ('id', '=', 6)]", help="Siapa yang bertanggung jawab") + user_id = fields.Many2one('res.users', string='Responsible', help="Siapa yang bertanggung jawab") def _compute_vendor_ids(self): for manufacture in self: diff --git a/indoteknik_custom/security/ir.model.access.csv b/indoteknik_custom/security/ir.model.access.csv index e362e546..ff467204 100755 --- a/indoteknik_custom/security/ir.model.access.csv +++ b/indoteknik_custom/security/ir.model.access.csv @@ -77,4 +77,8 @@ access_cost_centre,access.cost.centre,model_cost_centre,,1,1,1,1 access_stock_scheduler_compute,access.stock.scheduler.compute,model_stock_scheduler_compute,,1,1,1,1 access_sale_order_promotion,access.sale.order.promotion,model_sale_order_promotion,,1,1,1,1 access_sale_orders_multi_update,access.sale.orders.multi_update,model_sale_orders_multi_update,,1,1,1,1 -access_quotation_so_multi_update,access.quotation.so.multi_update,model_quotation_so_multi_update,,1,1,1,1
\ No newline at end of file +access_quotation_so_multi_update,access.quotation.so.multi_update,model_quotation_so_multi_update,,1,1,1,1 +access_product_monitoring,access.product.monitoring,model_product_monitoring,,1,1,1,1 +access_customer_commision,access.customer.commision,model_customer_commision,,1,1,1,1 +access_customer_commision_line,access.customer.commision.line,model_customer_commision_line,,1,1,1,1 +access_customer_rebate,access.customer.rebate,model_customer_rebate,,1,1,1,1
\ No newline at end of file diff --git a/indoteknik_custom/views/account_bank_statement.xml b/indoteknik_custom/views/account_bank_statement.xml new file mode 100644 index 00000000..db380f37 --- /dev/null +++ b/indoteknik_custom/views/account_bank_statement.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <data> + <record id="account_bank_statement_tree_inherit" model="ir.ui.view"> + <field name="name">account.bank.statement.tree</field> + <field name="model">account.bank.statement</field> + <field name="inherit_id" ref="account.view_bank_statement_tree"/> + <field name="arch" type="xml"> + <field name="state" position="after"> + <field name="is_edit"/> + </field> + </field> + </record> + + <record id="account_bank_statement_form_inherit" model="ir.ui.view"> + <field name="name">account.bank.statement.form</field> + <field name="model">account.bank.statement</field> + <field name="inherit_id" ref="account.view_bank_statement_form"/> + <field name="arch" type="xml"> + <button name="button_reprocess" position="after"> + <button string="Unlock" class="oe_highlight" name="is_edited" type="object" attrs="{'invisible':['|', '|', ('is_edit', '=', True), ('line_ids','=',[]), ('state', '!=', 'confirm')]}"/> + + <button string="Lock" class="oe_highlight" name="not_edited" type="object" attrs="{'invisible':['|', '|', ('is_edit', '=', False), ('line_ids','=',[]), ('state', '!=', 'confirm')]}"/> + </button> + <field name="date" position="after"> + <field name="is_edit" invisible="1"/> + </field> + </field> + </record> + </data> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/account_move.xml b/indoteknik_custom/views/account_move.xml index c45dab25..1721abb6 100644 --- a/indoteknik_custom/views/account_move.xml +++ b/indoteknik_custom/views/account_move.xml @@ -13,6 +13,9 @@ <field name="invoice_date" position="after"> <field name="payment_schedule" attrs="{'invisible': [('move_type', '!=', 'in_invoice')]}"/> </field> + <field name="payment_reference" position="after"> + <field name="date_completed" readonly="1" attrs="{'invisible': [('move_type', '!=', 'out_invoice')]}"/> + </field> <field name="efaktur_document" position="before"> <field name="no_faktur_pajak" readonly="1"/> </field> @@ -28,7 +31,7 @@ <field name="counter"/> </field> <notebook position="inside"> - <page string="Due Extension"> + <page string="Due Extension" attrs="{'invisible': [('move_type', '!=', 'out_invoice')]}"> <field name="due_line"> <tree> <field name="due_id"/> @@ -70,8 +73,12 @@ <field name="model">account.move</field> <field name="inherit_id" ref="account.view_in_invoice_tree"/> <field name="arch" type="xml"> - <field name="payment_state" position="after"> - <field name="payment_schedule" optional="hide"/> + <field name="invoice_date_due" position="after"> + <field name="bill_day_to_due" string="Due Date" widget="remaining_days"/> + </field> + + <field name="invoice_date_due" position="attributes"> + <attribute name="invisible">1</attribute> </field> </field> </record> diff --git a/indoteknik_custom/views/automatic_purchase.xml b/indoteknik_custom/views/automatic_purchase.xml index 49751f4e..0478304e 100644 --- a/indoteknik_custom/views/automatic_purchase.xml +++ b/indoteknik_custom/views/automatic_purchase.xml @@ -10,6 +10,7 @@ <field name="description"/> <field name="notification" readonly="1"/> <field name="is_po" readonly="1"/> + <field name="responsible_id"/> </tree> </field> </record> @@ -57,6 +58,7 @@ <group> <field name="date_doc"/> <field name="vendor_id"/> + <field name="responsible_id"/> <field name="description"/> <field name="notification" readonly="1"/> </group> diff --git a/indoteknik_custom/views/customer_commision.xml b/indoteknik_custom/views/customer_commision.xml new file mode 100644 index 00000000..008c79f8 --- /dev/null +++ b/indoteknik_custom/views/customer_commision.xml @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <record id="customer_commision_tree" model="ir.ui.view"> + <field name="name">customer.commision.tree</field> + <field name="model">customer.commision</field> + <field name="arch" type="xml"> + <tree> + <field name="number"/> + <field name="date_from"/> + <field name="date_to"/> + <field name="partner_id"/> + <field name="description"/> + <field name="notification" readonly="1"/> + <field name="status" readonly="1"/> + </tree> + </field> + </record> + + <record id="customer_commision_line_tree" model="ir.ui.view"> + <field name="name">customer.commision.line.tree</field> + <field name="model">customer.commision.line</field> + <field name="arch" type="xml"> + <tree editable="top" create="false"> + <field name="partner_id" readonly="1"/> + <field name="invoice_id" readonly="1"/> + <field name="state" readonly="1"/> + <field name="product_id" readonly="1" optional="hide"/> + <field name="dpp" readonly="1"/> + <field name="tax" readonly="1" optional="hide"/> + <field name="total" readonly="1" optional="hide"/> + </tree> + </field> + </record> + + <record id="customer_commision_form" model="ir.ui.view"> + <field name="name">customer_commision_form</field> + <field name="model">customer.commision</field> + <field name="arch" type="xml"> + <form> + <header> + <button name="action_confirm_customer_commision" + string="Confirm" type="object" + options="{}"/> + </header> + <sheet string="Customer Commision"> + <div class="oe_button_box" name="button_box"/> + <group> + <group> + <field name="number"/> + <field name="date_from"/> + <field name="partner_id"/> + <field name="description"/> + <field name="commision_percent"/> + <field name="commision_amt"/> + </group> + <group> + <div> + <button name="generate_customer_commision" + string="Generate Line" + type="object" + class="mr-2 oe_highlight" + /> + </div> + <field name="date_to"/> + <field name="commision_type"/> + <field name="notification" readonly="1"/> + <field name="status" readonly="1"/> + <field name="total_dpp"/> + </group> + </group> + <notebook> + <page string="Lines"> + <field name="commision_lines"/> + </page> + </notebook> + </sheet> + <div class="oe_chatter"> + <field name="message_follower_ids" widget="mail_followers"/> + <field name="message_ids" widget="mail_thread"/> + </div> + </form> + </field> + </record> + + <record id="customer_commision_action" model="ir.actions.act_window"> + <field name="name">Customer Commision</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">customer.commision</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem id="menu_customer_commision_acct" + name="Customer Commision" + action="customer_commision_action" + parent="account.menu_finance_entries" + sequence="113" + /> + + <menuitem id="menu_customer_commision_sales" + name="Customer Commision" + action="customer_commision_action" + parent="sale.product_menu_catalog" + sequence="101" + /> + + <record id="customer_rebate_tree" model="ir.ui.view"> + <field name="name">customer.rebate.tree</field> + <field name="model">customer.rebate</field> + <field name="arch" type="xml"> + <tree> + <field name="partner_id"/> + <field name="date_from"/> + <field name="date_to"/> + <field name="description"/> + <field name="target_1st"/> + <field name="target_2nd"/> + <field name="achieve_1"/> + <field name="achieve_2"/> + <field name="dpp_q1" optional="hide"/> + <field name="dpp_q2" optional="hide"/> + <field name="dpp_q3" optional="hide"/> + <field name="dpp_q4" optional="hide"/> + <field name="status_q1" optional="hide"/> + <field name="status_q2" optional="hide"/> + <field name="status_q3" optional="hide"/> + <field name="status_q4" optional="hide"/> + </tree> + </field> + </record> + + <record id="customer_rebate_form" model="ir.ui.view"> + <field name="name">customer_rebate_form</field> + <field name="model">customer.rebate</field> + <field name="arch" type="xml"> + <form> + <sheet string="Customer Rebate"> + <div class="oe_button_box" name="button_box"/> + <group> + <group> + <field name="date_from"/> + <field name="partner_id"/> + <field name="target_1st"/> + <field name="target_2nd"/> + <field name="dpp_q1"/> + <field name="dpp_q2"/> + <field name="dpp_q3"/> + <field name="dpp_q4"/> + </group> + <group> + <field name="date_to"/> + <field name="description"/> + <field name="achieve_1"/> + <field name="achieve_2"/> + <field name="status_q1"/> + <field name="status_q2"/> + <field name="status_q3"/> + <field name="status_q4"/> + </group> + </group> + </sheet> + <div class="oe_chatter"> + <field name="message_follower_ids" widget="mail_followers"/> + <field name="message_ids" widget="mail_thread"/> + </div> + </form> + </field> + </record> + + <record id="customer_rebate_action" model="ir.actions.act_window"> + <field name="name">Customer Rebate</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">customer.rebate</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem id="menu_customer_rebate_acct" + name="Customer Rebate" + action="customer_rebate_action" + parent="account.menu_finance_entries" + sequence="114" + /> + + <menuitem id="menu_customer_rebate_sales" + name="Customer Rebate" + action="customer_rebate_action" + parent="sale.product_menu_catalog" + sequence="102" + /> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/ir_sequence.xml b/indoteknik_custom/views/ir_sequence.xml index 6798e5b4..86259b12 100644 --- a/indoteknik_custom/views/ir_sequence.xml +++ b/indoteknik_custom/views/ir_sequence.xml @@ -60,5 +60,15 @@ <field name="number_next">1</field> <field name="number_increment">1</field> </record> + + <record id="sequence_commision_customer" model="ir.sequence"> + <field name="name">Customer Commision</field> + <field name="code">customer.commision</field> + <field name="active">TRUE</field> + <field name="prefix">CC/%(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/product_monitoring.xml b/indoteknik_custom/views/product_monitoring.xml new file mode 100644 index 00000000..779a7dd7 --- /dev/null +++ b/indoteknik_custom/views/product_monitoring.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + <record id="product_monitoring_tree" model="ir.ui.view"> + <field name="name">product.monitoring.tree</field> + <field name="model">product.monitoring</field> + <field name="arch" type="xml"> + <tree create="false" multi_edit="1"> + <field name="product_id"/> + <field name="outgoing_qty"/> + <field name="incoming_qty"/> + <field name="qty_available"/> + <field name="qty_upcoming"/> + <field name="status_stock" + widget="badge" + decoration-danger="status_stock == 'outgoing_gt_stock'" + decoration-success="status_stock == 'outgoing_lt_stock'" + /> + </tree> + </field> + </record> + + <record id="product_monitoring_form" model="ir.ui.view"> + <field name="name">product.monitoring.form</field> + <field name="model">product.monitoring</field> + <field name="arch" type="xml"> + <form create="false" edit="false"> + <sheet> + <group> + <group> + <field name="product_id"/> + <field name="outgoing_qty"/> + <field name="incoming_qty"/> + <field name="qty_available"/> + </group> + </group> + </sheet> + </form> + </field> + </record> + + <record id="product_monitoring_action" model="ir.actions.act_window"> + <field name="name">Product Monitoring</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">product.monitoring</field> + <field name="view_mode">tree,form</field> + </record> + + <menuitem + id="menu_product_monitoring_in_purchase" + name="Product Monitoring" + parent="menu_monitoring_in_purchase" + sequence="1" + action="product_monitoring_action" + /> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/product_template.xml b/indoteknik_custom/views/product_template.xml index a3a23101..92d2191e 100755 --- a/indoteknik_custom/views/product_template.xml +++ b/indoteknik_custom/views/product_template.xml @@ -10,9 +10,11 @@ <field name="web_tax_id"/> <field name="x_manufacture"/> <field name="x_model_product"/> + <field name="kind_of"/> <field name="x_studio_field_tGhJR" widget="many2many_tags"/> </field> <field name="uom_po_id" position="after"> + <field name="unpublished" /> <field name="desc_update_solr" readonly="1" /> <field name="last_update_solr" readonly="1" /> </field> diff --git a/indoteknik_custom/views/purchase_order.xml b/indoteknik_custom/views/purchase_order.xml index e0ec86f9..bc84bcd1 100755 --- a/indoteknik_custom/views/purchase_order.xml +++ b/indoteknik_custom/views/purchase_order.xml @@ -37,7 +37,7 @@ <field name="currency_id" position="after"> <field name="summary_qty_po"/> <field name="count_line_product"/> - <field name="payment_term_id"/> + <field name="payment_term_id" required="1"/> </field> <field name="amount_total" position="after"> <field name="total_margin"/> @@ -65,6 +65,7 @@ </field> <field name="price_subtotal" position="after"> <field name="so_line_id" attrs="{'readonly': 1}" optional="hide"/> + <field name="indent" optional="hide"/> </field> <page name="purchase_delivery_invoice" position="after"> <page name="purchase_vendor_bills" string="Vendor Bills" groups="indoteknik_custom.technical_administrator"> @@ -75,8 +76,10 @@ </page> <field name="fiscal_position_id" position="after"> <field name="note_description"/> + <field name="description"/> <field name="total_so_percent_margin"/> <field name="has_active_invoice" invisible="1" /> + <field name="responsible_ids" widget="many2many_tags"/> </field> <field name="order_line" position="attributes"> @@ -94,6 +97,12 @@ <xpath expr="//form/sheet/notebook/page/field[@name='order_line']/tree/field[@name='product_qty']" position="attributes"> <attribute name="attrs">{'readonly': [], 'required': True}</attribute> </xpath> + + <xpath expr="//form/sheet/notebook/page[@name='purchase_delivery_invoice']" position="before"> + <page string="Indent" name="purchase_order_lines_indent"> + <field name="purchase_order_lines"/> + </page> + </xpath> </field> </record> </data> @@ -106,6 +115,7 @@ <field name="arch" type="xml"> <field name="create_date" position="after"> <field name="approval_status" /> + <field name="responsible_ids" widget="many2many_tags" optional="hide"/> </field> </field> </record> @@ -121,6 +131,7 @@ <field name="po_status"/> <field name="note_description" optional="hide"/> <field name="sale_order_id" optional="hide"/> + <field name="responsible_ids" widget="many2many_tags" optional="hide"/> </field> </field> </record> @@ -138,7 +149,7 @@ </record> </data> <data> - <record id="purchase_order_search_inherit" model="ir.ui.view"> + <record id="rfq_order_search_inherit" model="ir.ui.view"> <field name="name">purchase.order.select.inherit</field> <field name="model">purchase.order</field> <field name="inherit_id" ref="purchase.view_purchase_order_filter"/> @@ -149,4 +160,30 @@ </field> </record> </data> + <data> + <record id="cron_stock_scheduler_compute" model="ir.cron"> + <field name="name">Run Scheduler Reserve Stock</field> + <field name="interval_number">1</field> + <field name="interval_type">hours</field> + <field name="numbercall">-1</field> + <field name="doall" eval="False"/> + <field name="model_id" ref="model_stock_scheduler_compute"/> + <field name="code">model.procure_calculation()</field> + <field name="state">code</field> + <field name="priority">75</field> + <field name="active">True</field> + </record> + </data> + <data> + <record id="purchase_order_line_indent_tree" model="ir.ui.view"> + <field name="name">purchase.order.line.indent.tree</field> + <field name="model">purchase.order.line</field> + <field name="arch" type="xml"> + <tree editable="top" create="false" delete="false"> + <field name="product_id" readonly="1"/> + <field name="indent"/> + </tree> + </field> + </record> + </data> </odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/purchase_pricelist.xml b/indoteknik_custom/views/purchase_pricelist.xml index f9fd52ba..f4cd4e78 100755 --- a/indoteknik_custom/views/purchase_pricelist.xml +++ b/indoteknik_custom/views/purchase_pricelist.xml @@ -11,6 +11,8 @@ <field name="system_price"/> <field name="human_last_update"/> <field name="system_last_update"/> + <field name="count_trx_po"/> + <field name="count_trx_po_vendor"/> </tree> </field> </record> @@ -27,6 +29,10 @@ <field name="vendor_id" context="{'res_partner_search_mode': 'supplier'}"/> <field name="product_price"/> <field name="system_price"/> + <field name="human_last_update"/> + <field name="system_last_update"/> + <field name="count_trx_po"/> + <field name="count_trx_po_vendor"/> </group> </group> </sheet> diff --git a/indoteknik_custom/views/requisition.xml b/indoteknik_custom/views/requisition.xml index e7335a57..e9c3b4e0 100644 --- a/indoteknik_custom/views/requisition.xml +++ b/indoteknik_custom/views/requisition.xml @@ -62,16 +62,6 @@ </group> <group> <div> - <button name="create_requisition_from_sales" - string="Create Line" - type="object" - class="mr-2 oe_highlight" - /> - <button name="create_requisition_from_sales_with_price" - string="Create Line with Price" - type="object" - class="mr-2 oe_highlight" - /> <button name="create_po_from_requisition" string="Create PO" type="object" @@ -82,13 +72,26 @@ </group> <notebook> <page string="Lines"> - <field name="requisition_lines"/> + <field name="requisition_lines"> + <tree editable="line"> + <field name="product_id"/> + <field name="partner_id"/> + <field name="qty_purchase"/> + <field name="price_unit"/> + <field name="subtotal"/> + <field name="brand_id"/> + </tree> + </field> </page> <page string="Matches"> <field name="requisition_match"/> </page> </notebook> </sheet> + <div class="oe_chatter"> + <field name="message_follower_ids" widget="mail_followers"/> + <field name="message_ids" widget="mail_thread"/> + </div> </form> </field> </record> diff --git a/indoteknik_custom/views/res_partner.xml b/indoteknik_custom/views/res_partner.xml index d609fdd5..c1ae3ed3 100644 --- a/indoteknik_custom/views/res_partner.xml +++ b/indoteknik_custom/views/res_partner.xml @@ -14,6 +14,8 @@ <field name="industry_id" position="after"> <field name="company_type_id"/> <field name="group_partner_id"/> + <field name="is_potential"/> + <field name="digital_invoice_tax"/> </field> <field name="npwp" position="before"> <field name="customer_type"/> diff --git a/indoteknik_custom/views/sale_monitoring.xml b/indoteknik_custom/views/sale_monitoring.xml index 641eb8fb..207277af 100755 --- a/indoteknik_custom/views/sale_monitoring.xml +++ b/indoteknik_custom/views/sale_monitoring.xml @@ -4,7 +4,7 @@ <field name="name">sale.monitoring.tree</field> <field name="model">sale.monitoring</field> <field name="arch" type="xml"> - <tree create="false" multi_edit="1"> + <tree create="false" multi_edit="1" default_order="date_order asc"> <header> <button name="action_refresh" string="Refresh" class="oe_highlight" type="object" /> </header> @@ -18,6 +18,7 @@ <field name="qty_po_received"/> <field name="qty_so_delivered"/> <field name="qty_so_invoiced"/> + <field name="purchase_representative_id"/> <field name="status" widget="badge" decoration-danger="status == 'Belum/Kurang PO'" @@ -25,7 +26,8 @@ decoration-success="status == 'Siap kirim'" decoration-info="status == 'Delivered' or status == 'Invoiced'" /> - <field name="note"/> + <field name="note_so_line"/> + <field name="note" optional="hide"/> </tree> </field> </record> @@ -49,7 +51,8 @@ decoration-info="status == 'Delivered' or status == 'Invoiced'" /> <field name="po_number"/> - <field name="note"/> + <field name="note_so_line"/> + <field name="note" optional="hide"/> </group> <group> <field name="qty_so"/> @@ -58,6 +61,7 @@ <field name="qty_po_received"/> <field name="qty_so_delivered"/> <field name="qty_so_invoiced"/> + <field name="purchase_representative_id"/> </group> </group> </sheet> diff --git a/indoteknik_custom/views/sale_order.xml b/indoteknik_custom/views/sale_order.xml index e0e9ac54..125296e3 100755 --- a/indoteknik_custom/views/sale_order.xml +++ b/indoteknik_custom/views/sale_order.xml @@ -45,12 +45,12 @@ <field name="helper_by_id" readonly="1"/> </field> <field name="analytic_account_id" position="after"> - <field name="customer_type" attrs="{'required': ['|', ('create_date', '>', '2023-06-28'), ('create_date', '=', False)]}"/> - <field name="npwp" placeholder='99.999.999.9-999.999' attrs="{'required': ['|', ('create_date', '>', '2023-06-28'), ('create_date', '=', False)]}"/> - <field name="sppkp" attrs="{'invisible': [('customer_type','!=','pkp')], 'required': [('customer_type', '=', 'pkp')]}"/> + <field name="customer_type" required="1"/> + <field name="npwp" placeholder='99.999.999.9-999.999' required="1"/> + <field name="sppkp" attrs="{'required': [('customer_type', '=', 'pkp')]}"/> <field name="email" required="1"/> <field name="due_id" readonly="1"/> - <field name="source_id" domain="[('id', 'in', [32, 59, 60, 61])]" attrs="{'required':[('create_date', '>', '2023-09-10')]}"/> + <field name="source_id" domain="[('id', 'in', [32, 59, 60, 61])]" required="1"/> </field> <field name="partner_shipping_id" position="after"> <field name="real_shipping_id"/> @@ -92,6 +92,7 @@ "/> <field name="purchase_tax_id" attrs="{'readonly': [('parent.approval_status', '!=', False)]}" domain="[('type_tax_use','=','purchase')]"/> <field name="item_percent_margin"/> + <field name="note" optional="hide"/> <field name="note_procurement" optional="hide"/> <field name="vendor_subtotal" optional="hide"/> <field name="amount_voucher_disc" string="Voucher" readonly="1" optional="hide"/> diff --git a/indoteknik_custom/views/stock_picking.xml b/indoteknik_custom/views/stock_picking.xml index 9f03235d..b0932d5a 100644 --- a/indoteknik_custom/views/stock_picking.xml +++ b/indoteknik_custom/views/stock_picking.xml @@ -15,6 +15,7 @@ <field name="driver_departure_date" optional="hide"/> <field name="driver_arrival_date" optional="hide"/> <field name="note_logistic" optional="hide"/> + <field name="note" optional="hide"/> </field> <field name="partner_id" position="after"> <field name="purchase_representative_id"/> @@ -71,6 +72,7 @@ /> </field> <field name="group_id" position="before"> + <field name="date_reserved"/> <field name="is_internal_use" string="Internal Use" type="object" diff --git a/indoteknik_custom/views/stock_warehouse_orderpoint.xml b/indoteknik_custom/views/stock_warehouse_orderpoint.xml new file mode 100644 index 00000000..038b09cc --- /dev/null +++ b/indoteknik_custom/views/stock_warehouse_orderpoint.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<odoo> + <data> + <record id="stock_warehouse_orderpoint_inherit" model="ir.ui.view"> + <field name="name">stock.warehouse.orderpoint.tree</field> + <field name="model">stock.warehouse.orderpoint</field> + <field name="inherit_id" ref="stock.view_warehouse_orderpoint_tree_editable_config"/> + <field name="arch" type="xml"> + <field name="product_uom_name" position="after"> + <field name="responsible_id" optional="hide"/> + </field> + </field> + </record> + </data> +</odoo>
\ No newline at end of file diff --git a/indoteknik_custom/views/users.xml b/indoteknik_custom/views/users.xml index d67b4474..020d8ddc 100644 --- a/indoteknik_custom/views/users.xml +++ b/indoteknik_custom/views/users.xml @@ -13,6 +13,7 @@ <field name="is_leader"/> <field name="is_logistic_approver"/> <field name="is_editor_product"/> + <field name="is_admin_reconcile"/> </field> </field> </record> diff --git a/indoteknik_custom/views/x_manufactures.xml b/indoteknik_custom/views/x_manufactures.xml index f68a0e00..d413be12 100755 --- a/indoteknik_custom/views/x_manufactures.xml +++ b/indoteknik_custom/views/x_manufactures.xml @@ -24,6 +24,7 @@ <field name="x_manufacture_service_center"/> <field name="cache_reset_status"/> <field name="parent_id"/> + <field name="user_id" optional="hide"/> </tree> </field> </record> @@ -46,6 +47,7 @@ <field name="cache_reset_status"/> <field name="parent_id"/> <field name="category_ids" widget="many2many_tags"/> + <field name="user_id"/> </group> <group> <field name="x_logo_manufacture" widget="image"/> |
