diff --git a/bahmni_account/__manifest__.py b/bahmni_account/__manifest__.py index 71e768d..7450838 100644 --- a/bahmni_account/__manifest__.py +++ b/bahmni_account/__manifest__.py @@ -14,6 +14,8 @@ 'data': [ 'views/account_invoice_view.xml', 'views/company_view.xml', + 'views/account_report.xml', + 'report/report_invoice_inherit.xml', ], 'demo': [], 'qweb': [], diff --git a/bahmni_account/models/account_invoice.py b/bahmni_account/models/account_invoice.py index 08f3424..c3d61da 100644 --- a/bahmni_account/models/account_invoice.py +++ b/bahmni_account/models/account_invoice.py @@ -1,18 +1,17 @@ +from collections import defaultdict +from contextlib import ExitStack, contextmanager + from odoo import fields, models, api, _ from odoo.exceptions import UserError, ValidationError import logging _logger = logging.getLogger(__name__) -# mapping invoice type to refund type -TYPE2REFUND = { - 'out_invoice': 'out_refund', # Customer Invoice - 'in_invoice': 'in_refund', # Vendor Bill - 'out_refund': 'out_invoice', # Customer Refund - 'in_refund': 'in_invoice', # Vendor Refund -} + class AccountInvoice(models.Model): _inherit = 'account.move' + order_id = fields.Many2one('sale.order',string="Sale ID") + discount_type = fields.Selection([('none', 'No Discount'), ('fixed', 'Fixed'), ('percentage', 'Percentage')], @@ -22,9 +21,18 @@ class AccountInvoice(models.Model): discount_percentage = fields.Float(string="Discount Percentage") disc_acc_id = fields.Many2one('account.account', string="Discount Account Head") - round_off_amount = fields.Monetary(string="Round Off Amount", - ) + round_off_amount = fields.Monetary(string="Round Off Amount") + @contextmanager + def _check_balanced(self, container): + ''' Assert the move is fully balanced debit = credit. + An error is raised if it's not the case. + ''' + with self._disable_recursion(container, 'check_move_validity', default=True, target=False) as disabled: + yield + if disabled: + return + unbalanced_moves = self._get_unbalanced_moves(container) @api.onchange('invoice_line_ids') def onchange_invoice_lines(self): amount_total = self.amount_untaxed + self.amount_tax @@ -41,36 +49,7 @@ def onchange_discount(self): if self.discount_percentage: self.discount = amount_total * self.discount_percentage / 100 - def _find_batch(self, product, qty, location, picking): - _logger.info("\n\n***** Product :%s, Quantity :%s Location :%s\n*****",product,qty,location) - lot_objs = self.env['stock.production.lot'].search([('product_id','=',product.id),('life_date','>=',str(fields.datetime.now()))]) - _logger.info('\n *** Searched Lot Objects:%s \n',lot_objs) - if any(lot_objs): - #Sort losts based on the expiry date FEFO(First Expiry First Out) - lot_objs = list(lot_objs) - sorted_lot_list = sorted(lot_objs, key=lambda l: l.life_date) - _logger.info('\n *** Sorted based on FEFO :%s \n',sorted_lot_list) - done_qty = qty - res_lot_ids = [] - lot_ids_for_query = tuple([lot.id for lot in sorted_lot_list]) - self._cr.execute("SELECT SUM(qty) FROM stock_quant WHERE lot_id IN %s and location_id=%s",(lot_ids_for_query,location.id,)) - qry_rslt = self._cr.fetchall() - available_qty = qry_rslt[0] and qry_rslt[0][0] or 0 - if available_qty >= qty: - for lot_obj in sorted_lot_list: - quants = lot_obj.quant_ids.filtered(lambda q: q.location_id == location) - for quant in quants: - if done_qty >= 0: - res_lot_ids.append(lot_obj) - done_qty = done_qty - quant.qty - return res_lot_ids - else: - message = ("Auto validation Failed
Reason: There are not enough stock available for %s product on %s Location") % (product.id,product.name,location.id,location.name) - picking.message_post(body=message) - else: - message = ("Auto validation Failed
Reason: There are no Batches/Serial no's available for %s product") % (product.id,product.name) - picking.message_post(body=message) - return False + def button_dummy(self): return True @@ -81,18 +60,14 @@ def button_dummy(self): def action_post(self): for inv in self: - print("inv",inv.discount,inv.round_off_amount,inv.amount_total) find_val = (inv.amount_total - inv.discount ) + inv.round_off_amount - print("find_val",find_val) differnece_vals = inv.amount_total - find_val - print("differnece_vals",differnece_vals) for move_line in inv.line_ids: update = False - print("move_line",move_line.display_type) if move_line.display_type =='payment_term': move_line.debit = move_line.debit - differnece_vals @@ -106,63 +81,10 @@ def action_post(self): other_moves._post(soft=False) return False +class AccountPayment(models.Model): + _inherit = 'account.payment' + + def invoice_seach(self): + """ Using ref find the invoice obj """ + return self.env['account.move'].search([('name', '=', self.move_id.ref),('move_type', '=', 'out_invoice')], limit=1) - - @api.model - def _prepare_refund(self, invoice, date_invoice=None, date=None, description=None, journal_id=None): - """ Prepare the dict of values to create the new refund from the invoice. - This method may be overridden to implement custom - refund generation (making sure to call super() to establish - a clean extension chain). - - :param record invoice: invoice to refund - :param string date_invoice: refund creation date from the wizard - :param integer date: force date from the wizard - :param string description: description of the refund from the wizard - :param integer journal_id: account.journal from the wizard - :return: dict of value to create() the refund - """ - values = {} - for field in self._get_refund_copy_fields(): - if invoice._fields[field].type == 'many2one': - values[field] = invoice[field].id - else: - values[field] = invoice[field] or False - - values['invoice_line_ids'] = self._refund_cleanup_lines(invoice.invoice_line_ids) - tax_lines = invoice.tax_line_ids - taxes_to_change = { - line.tax_id.id: line.tax_id.refund_account_id.id - for line in tax_lines.filtered(lambda l: l.tax_id.refund_account_id != l.tax_id.account_id) - } - cleaned_tax_lines = self._refund_cleanup_lines(tax_lines) - values['tax_line_ids'] = self._refund_tax_lines_account_change(cleaned_tax_lines, taxes_to_change) - - if journal_id: - journal = self.env['account.journal'].browse(journal_id) - elif invoice['type'] == 'in_invoice': - journal = self.env['account.journal'].search([('type', '=', 'purchase')], limit=1) - else: - journal = self.env['account.journal'].search([('type', '=', 'sale')], limit=1) - values['journal_id'] = journal.id - - values['type'] = TYPE2REFUND[invoice['type']] - values['date_invoice'] = date_invoice or fields.Date.context_today(invoice) - values['state'] = 'draft' - values['number'] = False - values['origin'] = invoice.number - values['payment_term_id'] = False - values['refund_invoice_id'] = invoice.id - #=============Customized code starts========= Added Custom discount fields in refund - values['discount_type'] = invoice.discount_type - values['discount'] = invoice.discount - values['discount_percentage'] = invoice.discount_percentage - values['disc_acc_id'] = invoice.disc_acc_id.id - #===========Customized code ends============= - - if date: - values['date'] = date - if description: - values['name'] = description - return values - diff --git a/bahmni_account/models/account_invoice_line.py b/bahmni_account/models/account_invoice_line.py index 9e5b69c..7a39fdb 100644 --- a/bahmni_account/models/account_invoice_line.py +++ b/bahmni_account/models/account_invoice_line.py @@ -4,39 +4,3 @@ class AccountInvoiceLine(models.Model): _inherit = 'account.move.line' - @api.model - def create(self, vals): - '''This method is overridden to update discount amount in invoice, - when invoice is getting created from sale order, and discount type selected in sale order is percentage. - Since, discount amount in readonly field and it gets updated by onchange method, which won't get called when invoice is created from backend.''' - if vals.get('invoice_id'): - invoice_obj = self.env['account.move'].browse(vals.get('invoice_id')) - amount_untaxed = 0.0 - amount_tax = 0.0 - # calculating total from already created invoice lines. - for ln in invoice_obj.invoice_line_ids: - amount_untaxed += ln.price_subtotal - taxes = ln.invoice_line_tax_ids.compute_all(ln.price_subtotal, invoice_obj.currency_id, - ln.quantity, product=ln.product_id, - partner=invoice_obj.partner_shipping_id) - amount_tax += sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])) - if vals.get('invoice_line_tax_ids'): - price_unit = vals.get('price_unit') * vals.get('quantity') - if vals.get('discount'): - price_unit = price_unit * (1 - vals['discount']/100) - amount_untaxed += price_unit - tax_ids = [] - if len(vals['invoice_line_tax_ids'][0]) == 3: - tax_ids = vals['invoice_line_tax_ids'][0][2] - elif len(vals['invoice_line_tax_ids'][0]) == 1: - tax_ids = vals['invoice_line_tax_ids'][0] - tax_obj = self.env['account.tax'].browse(tax_ids) - taxes = tax_obj.compute_all(price_unit, invoice_obj.currency_id, - vals.get('quantity'), product=vals.get('product_id'), - partner=invoice_obj.partner_id) - amount_tax += sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])) - if invoice_obj.discount_type == 'percentage': - discount_amount = (invoice_obj.currency_id.round(amount_untaxed) + - invoice_obj.currency_id.round(amount_tax)) * invoice_obj.discount_percentage / 100 - invoice_obj.write({'discount': discount_amount}) - return super(AccountInvoiceLine, self).create(vals) diff --git a/bahmni_account/report/onscreen_header_and_footer.xml b/bahmni_account/report/onscreen_header_and_footer.xml new file mode 100644 index 0000000..cef8c54 --- /dev/null +++ b/bahmni_account/report/onscreen_header_and_footer.xml @@ -0,0 +1,39 @@ + +
+
+
+

+

Phone :

+
+
+
+
+
+ +
+
+ + +
+ +
+ +
+
+
    +
    + +
    +
    + - +
    +
+
+ Page: of +
+
+ +
+
+
+
diff --git a/bahmni_account/report/report_invoice_inherit.xml b/bahmni_account/report/report_invoice_inherit.xml new file mode 100644 index 0000000..b1da8a3 --- /dev/null +++ b/bahmni_account/report/report_invoice_inherit.xml @@ -0,0 +1,252 @@ + + + + + + + diff --git a/bahmni_account/views/account_report.xml b/bahmni_account/views/account_report.xml new file mode 100644 index 0000000..efa07a6 --- /dev/null +++ b/bahmni_account/views/account_report.xml @@ -0,0 +1,29 @@ + + + + + + Receipt + account.payment + qweb-pdf + bahmni_account.report_invoice_recipt + bahmni_account.report_invoice_recipt + (object.move_id._get_report_base_filename()) + (object.state == 'posted') and ((object.name or 'INV').replace('/','_')+'.pdf') + + report + + + Receipt Summary + account.payment + qweb-pdf + bahmni_account.report_invoice_summarized_recipt + bahmni_account.report_invoice_summarized_recipt + (object.move_id._get_report_base_filename()) + (object.state == 'posted') and ((object.name or 'INV').replace('/','_')+'.pdf') + + report + + + + diff --git a/bahmni_api_feed/__manifest__.py b/bahmni_api_feed/__manifest__.py index 3b3cf22..6a28e67 100644 --- a/bahmni_api_feed/__manifest__.py +++ b/bahmni_api_feed/__manifest__.py @@ -10,16 +10,22 @@ 'category': 'Technical', 'website': '', 'images': [], - 'depends': ['base','product'], + 'depends': ['base','product','bahmni_sale'], 'data': [ 'security/ir.model.access.csv', - 'data/mrs_person_attributes_data.xml', 'views/event_records_view.xml', - 'views/res_company.xml', - 'views/order_type_view.xml', - 'views/syncable_units_mapping_view.xml', - 'views/order_type_shop_map_view.xml', - 'views/res_users_view.xml', + 'views/res_company.xml', + 'views/order_type_view.xml', + 'views/syncable_units_mapping_view.xml', + 'views/order_type_shop_map_view.xml', + 'views/res_users_view.xml', + 'data/mrs_person_attributes_data.xml', + 'views/menus.xml', + #'data/order_type.xml', + 'data/sale_shop.xml', + #'data/order_type_shop_map.xml', + 'data/syncable_units_mapping.xml', + ], 'demo': [], diff --git a/bahmni_api_feed/data/order_type.xml b/bahmni_api_feed/data/order_type.xml new file mode 100644 index 0000000..f4003af --- /dev/null +++ b/bahmni_api_feed/data/order_type.xml @@ -0,0 +1,14 @@ + + + + + Drug Order + + + Lab Order + + + Radiology Order + + + diff --git a/bahmni_api_feed/data/order_type_shop_map.xml b/bahmni_api_feed/data/order_type_shop_map.xml new file mode 100644 index 0000000..9cf67c7 --- /dev/null +++ b/bahmni_api_feed/data/order_type_shop_map.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/bahmni_api_feed/data/sale_shop.xml b/bahmni_api_feed/data/sale_shop.xml new file mode 100644 index 0000000..e1e5e79 --- /dev/null +++ b/bahmni_api_feed/data/sale_shop.xml @@ -0,0 +1,11 @@ + + + + + Pharmacy + 1 + 8 + 1 + + + diff --git a/bahmni_api_feed/data/syncable_units_mapping.xml b/bahmni_api_feed/data/syncable_units_mapping.xml new file mode 100644 index 0000000..a174007 --- /dev/null +++ b/bahmni_api_feed/data/syncable_units_mapping.xml @@ -0,0 +1,9 @@ + + + + + Unit + + + + diff --git a/bahmni_api_feed/models/api_event_worker.py b/bahmni_api_feed/models/api_event_worker.py index 77ea1ac..8ebbc64 100644 --- a/bahmni_api_feed/models/api_event_worker.py +++ b/bahmni_api_feed/models/api_event_worker.py @@ -14,8 +14,7 @@ class ApiEventWorker(models.Model): @api.model def process_event(self, vals): '''Method getting triggered from Bahmni side''' - _logger.info("vals") - _logger.info(vals) + _logger.info("Payload:" ,vals) category = vals.get("category") try: if category == "create.customer": @@ -95,7 +94,7 @@ def _get_address_details(self, address): @api.model def _find_country(self, address): - return self.env['res.company'].sudo().search([('id', '=', 2)]).partner_id.country_id + return self.env['res.company'].sudo().search([], limit=1).partner_id.country_id @api.model def _find_or_create_level3(self, state, district, level_name, auto_create_customer_address_levels): @@ -125,24 +124,24 @@ def _find_or_create_district(self, country, state, district_county_name, auto_cr def _find_or_create_state(self, country, state_province_name, auto_create_customer_address_levels): states = self.env['res.country.state'].search([('name', '=ilike', state_province_name), ('country_id', '=', country.id)]) - if not states and auto_create_customer_address_levels == '1': + if not states and auto_create_customer_address_levels: state_code = STATE_CODE_PREFIX + str(uuid.uuid4()) state = self.env['res.country.state'].create({'name': state_province_name, 'code': state_code, 'country_id': country.id}) else: - state = False + return states return state def _get_customer_vals(self, vals): res = {} res.update({'ref': vals.get('ref'), 'name': vals.get('name'), - 'local_name': vals.get('local_name'), + 'local_name': vals.get('local_name') if vals.get('local_name') else False, 'uuid': vals.get('uuid')}) address_data = vals.get('preferredAddress') # get validated address details - address_details = self._get_address_details(json.loads(address_data)) + address_details = self._get_address_details(address_data) # update address details res.update(address_details) # update other details : for now there is only scope of updating contact. @@ -151,17 +150,31 @@ def _get_customer_vals(self, vals): return res def _create_or_update_person_attributes(self, cust_id, vals): - attributes = json.loads(vals.get("attributes", "{}")) - if vals.get('village'): + attributes = vals.get("attributes", "{}") + address_data = vals.get('preferredAddress') + if address_data.get('cityVillage') and cust_id: village_master = self.env['village.village'] customer_master = self.env['res.partner'].sudo().search([('id', '=', cust_id)]) - identified_village = village_master.sudo().search([('name', '=', vals.get('village'))], limit=1) + identified_village = village_master.sudo().search([('name', '=', address_data.get('cityVillage'))], limit=1) if identified_village and customer_master: customer_master.village_id = identified_village.id else: - created_village = village_master.sudo().create({'name': vals.get('village')}) + created_village = village_master.sudo().create({'name': address_data.get('cityVillage')}) customer_master.village_id = created_village.id + if attributes['email'] and cust_id: + customer_master = self.env['res.partner'].sudo().search([('id', '=', cust_id)]) + if customer_master: + customer_master.email = attributes['email'] + customer_master.customer_rank = 1 ##Make a partner as a customer + + if address_data.get('country') and cust_id: + country_master = self.env['res.country'] + customer_master = self.env['res.partner'].sudo().search([('id', '=', cust_id)]) + identified_country = country_master.sudo().search([('name', '=', address_data.get('country'))], limit=1) + if identified_country: + customer_master.country_id = identified_country.id + for key in attributes: if key in [key for key in attributes]: column_dict = {'partner_id': cust_id} diff --git a/bahmni_api_feed/models/order_save_service.py b/bahmni_api_feed/models/order_save_service.py index ec25766..33724e1 100644 --- a/bahmni_api_feed/models/order_save_service.py +++ b/bahmni_api_feed/models/order_save_service.py @@ -27,9 +27,9 @@ def _get_openerp_orders(self, vals): def _get_warehouse_id(self, location, order_type_ref): _logger.info("\n identifying warehouse for warehouse %s, location %s", order_type_ref, location) if location: - operation_types = self.env['stock.picking.type'].search([('default_location_src_id', '=', location.id)]) + operation_types = self.env['stock.picking.type'].sudo().search([('default_location_src_id', '=', location.id)]) if operation_types: - mapping = self.env['order.picking.type.mapping'].search([('order_type_id', '=', order_type_ref.id), + mapping = self.env['order.picking.type.mapping'].sudo().search([('order_type_id', '=', order_type_ref.id), ('picking_type_id', 'in', operation_types.ids)], limit=1) if mapping: @@ -39,7 +39,7 @@ def _get_warehouse_id(self, location, order_type_ref): else: # either location should exist as stock location of a warehouse. - warehouse = self.env['stock.warehouse'].search([('lot_stock_id', '=', location.id)]) + warehouse = self.env['stock.warehouse'].sudo().search([('lot_stock_id', '=', location.id)]) if warehouse: return warehouse.id else: @@ -73,7 +73,6 @@ def _get_shop_and_location_id(self, orderType, location_name, order_type_record) if not shop_list_with_order_type: _logger.info("\nCouldn't identify OrderType-Shop mapping for Order Type [%s]", orderType) - #return False, False order_type = self.env['order.type'].sudo().search([('name', '=', orderType)], limit=1) location_rec = self.env['stock.location'].sudo().search([('name', '=', location_name)], limit=1) if not location_rec: @@ -81,7 +80,7 @@ def _get_shop_and_location_id(self, orderType, location_name, order_type_record) shop_list_with_order_type = OrderTypeShopMap.sudo().create({ "order_type": order_type.id if order_type else self.env['order.type'].sudo().create({'name': OrderType}), "location_name": location_name, - "shop_id": self.env['sale.shop'].search([('location_id', '=', location_rec.id)], limit=1).id, + "shop_id": self.env['sale.shop'].sudo().search([('location_id', '=', location_rec.id)], limit=1).id, "location_id": location_rec.id}) order_shop_map_object = shop_list_with_order_type[0] @@ -106,9 +105,6 @@ def create_orders(self, vals): location_name = vals.get("locationName") all_orders = self._get_openerp_orders(vals) - if not all_orders: - return "" - customer_ids = self.env['res.partner'].sudo().search([('ref', '=', customer_id)]) if customer_ids: cus_id = customer_ids[0] @@ -235,7 +231,7 @@ def create_orders(self, vals): 'origin': 'API FEED SYNC'} if shop_obj.pricelist_id: sale_order_dict.update({'pricelist_id': shop_obj.pricelist_id.id}) - new_sale_order = self.env['sale.order'].create(sale_order_dict) + new_sale_order = self.env['sale.order'].sudo().create(sale_order_dict) _logger.debug("\n Created a new Sale Order. ID: %s. Processing order lines ..", new_sale_order.id) for line in unprocessed_dispensed_order: self._process_orders(new_sale_order, unprocessed_dispensed_order, line) diff --git a/bahmni_sale/views/menus.xml b/bahmni_api_feed/views/menus.xml similarity index 100% rename from bahmni_sale/views/menus.xml rename to bahmni_api_feed/views/menus.xml diff --git a/bahmni_product/models/product.py b/bahmni_product/models/product.py index 800cdd4..b431b22 100644 --- a/bahmni_product/models/product.py +++ b/bahmni_product/models/product.py @@ -9,94 +9,18 @@ class ProductProduct(models.Model): _inherit = 'product.product' - @api.depends('stock_quant_ids', 'stock_move_ids') - def _compute_quantities(self): - res = self._compute_quantities_dict(self._context.get('lot_id'), self._context.get('owner_id'), self._context.get('package_id'), self._context.get('from_date'), self._context.get('to_date')) - for product in self: - product.qty_available = res[product.id]['qty_available'] - product.incoming_qty = res[product.id]['incoming_qty'] - product.outgoing_qty = res[product.id]['outgoing_qty'] - product.virtual_available = res[product.id]['virtual_available'] - product.actual_stock = res[product.id]['actual_stock'] - - def _compute_quantities_dict(self, lot_id, owner_id, package_id, from_date=False, to_date=False): - domain_quant_loc, domain_move_in_loc, domain_move_out_loc = self._get_domain_locations() - domain_quant = [('product_id', 'in', self.ids)] + domain_quant_loc - dates_in_the_past = False - if to_date and to_date < fields.Datetime.now(): #Only to_date as to_date will correspond to qty_available - dates_in_the_past = True - - domain_move_in = [('product_id', 'in', self.ids)] + domain_move_in_loc - domain_move_out = [('product_id', 'in', self.ids)] + domain_move_out_loc - if lot_id: - domain_quant += [('lot_id', '=', lot_id)] - if owner_id: - domain_quant += [('owner_id', '=', owner_id)] - domain_move_in += [('restrict_partner_id', '=', owner_id)] - domain_move_out += [('restrict_partner_id', '=', owner_id)] - if package_id: - domain_quant += [('package_id', '=', package_id)] - # if dates_in_the_past: - domain_move_in_done = list(domain_move_out) - domain_move_out_done = list(domain_move_in) - domain_quant_actual_stock = copy(domain_quant) - if from_date: - domain_move_in += [('date', '>=', from_date)] - domain_move_out += [('date', '>=', from_date)] - if to_date: - domain_quant_actual_stock += ['|', '&', ('lot_id', '!=', False), '|', ('lot_id.expiration_date', '>=', to_date), - ('lot_id.expiration_date', '=', False), ('lot_id', '=', False)] - domain_move_in += [('date', '<=', to_date)] - domain_move_out += [('date', '<=', to_date)] - else: - domain_quant_actual_stock += ['|', '&', ('lot_id', '!=', False), '|', ('lot_id.expiration_date', '>=', date.today().strftime(DF)), - ('lot_id.expiration_date', '=', False), ('lot_id', '=', False)] - Move = self.env['stock.move'] - Quant = self.env['stock.quant'] - domain_move_in_todo = [('state', 'not in', ('done', 'cancel', 'draft'))] + domain_move_in - domain_move_out_todo = [('state', 'not in', ('done', 'cancel', 'draft'))] + domain_move_out - moves_in_res = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_in_todo, ['product_id', 'product_qty'], ['product_id'], orderby='id')) - moves_out_res = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_out_todo, ['product_id', 'product_qty'], ['product_id'], orderby='id')) - quants_res = dict((item['product_id'][0], item['quantity']) for item in Quant.read_group(domain_quant, ['product_id', 'quantity'], ['product_id'], orderby='id')) - quants_res_actual_stock = dict((item['product_id'][0], item['quantity']) for item in Quant.read_group(domain_quant_actual_stock, ['product_id', 'quantity'], ['product_id'], orderby='id')) - # if dates_in_the_past: - # Calculate the moves that were done before now to calculate back in time (as most questions will be recent ones) - if to_date: - domain_move_in_done = [('state', '=', 'done'), ('date', '>', to_date)] + domain_move_in_done - domain_move_out_done = [('state', '=', 'done'), ('date', '>', to_date)] + domain_move_out_done - else: - domain_move_in_done = [('state', '=', 'done')] + domain_move_in_done - domain_move_out_done = [('state', '=', 'done')] + domain_move_out_done - moves_in_res_past = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_in_done, ['product_id', 'product_qty'], ['product_id'], orderby='id')) - moves_out_res_past = dict((item['product_id'][0], item['product_qty']) for item in Move.read_group(domain_move_out_done, ['product_id', 'product_qty'], ['product_id'], orderby='id')) - res = dict() - for product in self.with_context(prefetch_fields=False): - res[product.id] = {} - if dates_in_the_past: - actual_stock = quants_res_actual_stock.get(product.id, 0.0) - moves_in_res_past.get(product.id, 0.0) + moves_out_res_past.get(product.id, 0.0) - qty_available = quants_res.get(product.id, 0.0) - moves_in_res_past.get(product.id, 0.0) + moves_out_res_past.get(product.id, 0.0) - else: - qty_available = quants_res.get(product.id, 0.0) - actual_stock = quants_res_actual_stock.get(product.id, 0.0) - res[product.id]['qty_available'] = float_round(qty_available, precision_rounding=product.uom_id.rounding) - res[product.id]['actual_stock'] = float_round(actual_stock, precision_rounding=product.uom_id.rounding) - res[product.id]['incoming_qty'] = float_round(moves_in_res.get(product.id, 0.0), precision_rounding=product.uom_id.rounding) - res[product.id]['outgoing_qty'] = float_round(moves_out_res.get(product.id, 0.0), precision_rounding=product.uom_id.rounding) - res[product.id]['virtual_available'] = float_round( - qty_available + res[product.id]['incoming_qty'] - res[product.id]['outgoing_qty'], - precision_rounding=product.uom_id.rounding) - return res + stock_quant_ids = fields.One2many('stock.quant', 'product_id', help='Technical: used to compute quantities.') stock_move_ids = fields.One2many('stock.move', 'product_id', help='Technical: used to compute quantities.') - actual_stock = fields.Integer(string="Actual Stock", compute=_compute_quantities, + actual_stock = fields.Integer(string="Actual Stock", help="Get the actual stock available for product." "\nActual stock of product doesn't eliminates the count of expired lots from available quantities.") mrp = fields.Float(string="MRP") # when variants exists for product, then mrp will be defined at variant level. uuid = fields.Char(string="UUID") free_qty = fields.Float( - 'Free To Use Quantity ', compute='_compute_quantities', search='_search_free_qty', + 'Free To Use Quantity ', search='_search_free_qty', digits='Product Unit of Measure', compute_sudo=False,store=True, help="Forecast quantity (computed as Quantity On Hand " "- reserved quantity)\n" @@ -138,43 +62,9 @@ def name_get(self): class ProductTemplate(models.Model): _inherit = 'product.template' - def _compute_quantities(self): - res = self._compute_quantities_dict() - for template in self: - template.qty_available = res[template.id]['qty_available'] - template.virtual_available = res[template.id]['virtual_available'] - template.incoming_qty = res[template.id]['incoming_qty'] - template.outgoing_qty = res[template.id]['outgoing_qty'] - template.actual_stock = res[template.id]['actual_stock'] - - def _compute_quantities_dict(self): - - variants_available = { - p['id']: p for p in self.product_variant_ids._origin.read(['qty_available', 'virtual_available', 'incoming_qty', 'outgoing_qty','actual_stock']) - } - print("variants_available",variants_available) - prod_available = {} - for template in self: - qty_available = 0 - virtual_available = 0 - incoming_qty = 0 - outgoing_qty = 0 - actual_stock = 0 - for p in template.product_variant_ids: - print("p.id",p.id) - qty_available += variants_available[p.id]["qty_available"] - virtual_available += variants_available[p.id]["virtual_available"] - incoming_qty += variants_available[p.id]["incoming_qty"] - outgoing_qty += variants_available[p.id]["outgoing_qty"] - actual_stock += variants_available[p.id]["actual_stock"] - prod_available[template.id] = { - "qty_available": qty_available, - "virtual_available": virtual_available, - "incoming_qty": incoming_qty, - "outgoing_qty": outgoing_qty, - "actual_stock": actual_stock, - } - return prod_available + + + uuid = fields.Char(string="UUID") mrp = fields.Float(string="MRP") @@ -183,27 +73,16 @@ def _compute_quantities_dict(self): drug = fields.Char(string="Drug Name", help="This field is for assigning Generic name to product") - actual_stock = fields.Integer(string="Actual Stock", compute=_compute_quantities, + actual_stock = fields.Integer(string="Actual Stock", help="Get the actual stock available for product." "\nActual stock of product doesn't eliminates the count of expired lots from available quantities.") - free_qty = fields.Integer(string="Free Qty", compute=_compute_quantities, + free_qty = fields.Integer(string="Free Qty", help="Get the actual stock available for product." "\nActual stock of product doesn't eliminates the count of expired lots from available quantities.") dhis2_code = fields.Char(string="DHIS2 Code") - def action_open_quants(self): - products = self.mapped('product_variant_ids') - action = self.env.ref('stock.product_open_quants').read()[0] - if self._context.get('show_actual_stock'): - action['domain'] = ['|', '&', ('lot_id', '!=', False), '|', ('lot_id.expiration_date', '>=', date.today().strftime(DF)), - ('lot_id.expiration_date', '=', False), ('lot_id', '=', False)] - action['domain'] += [('product_id', 'in', products.ids)] - else: - action['domain'] = [('product_id', 'in', products.ids)] - action['context'] = {'search_default_locationgroup': 1, 'search_default_internal_loc': 1} - return action @api.model def create(self, vals): diff --git a/bahmni_product/models/product_category.py b/bahmni_product/models/product_category.py index 17ee4a0..a3463f2 100644 --- a/bahmni_product/models/product_category.py +++ b/bahmni_product/models/product_category.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- + import uuid from odoo import models, fields, api diff --git a/bahmni_purchase/models/product.py b/bahmni_purchase/models/product.py index a61bb9f..295900e 100644 --- a/bahmni_purchase/models/product.py +++ b/bahmni_purchase/models/product.py @@ -4,77 +4,6 @@ class product_product(models.Model): _inherit = 'product.product' - def get_mrp(self, supplier_id, prod_qty, date=False, uom_id=False): - '''Method which will return mrp for an product from Vendor configuration if set, - else will return mrp configured in product master''' - seller = self._select_seller(partner_id=supplier_id, - quantity=self.product_qty, - date=date, - uom_id=uom_id) - if seller: - mrp = seller.mrp - else: - mrp = self.mrp - return mrp - def set_mrp(self, supplier_id, product_qty, mrp, price_unit, date=False, uom_id=False): - '''Method which will add vendor configuration if does not exists, - if exists it will set mrp in that.''' - seller = self._select_seller(partner_id=supplier_id, - quantity=self.product_qty, - date=date, - uom_id=uom_id) - if seller: - seller.mrp = mrp - else: - max_seq = self.env['product.supplierinfo'].search([], order='sequence desc', limit=1) - sequence = max_seq + 1 - self.env['product.supplierinfo'].create({'product_tmpl_id': self.product_tmpl_id.id, - 'name': supplier_id, - 'min_qty': product_qty, - 'price': price_unit, - 'mrp': mrp, - 'sequence': sequence}) - def _check_low_stock(self): - if self.type == 'product': - warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.company_id.id)]) - location_ids = [wh.lot_stock_id.id for wh in warehouse] - if self._context.get('location'): - location_ids = [self._context.get('location')] - for location in location_ids: - orderpoint = self.env['stock.warehouse.orderpoint'].search([('product_id', '=', self.id), - ('location_id', '=', location)]) - if orderpoint.product_min_qty > self.with_context({'location': location}).virtual_available: - self.low_stock = True - return True - self.low_stock = False - - def _search_low_stock(self, operator, value): - '''Method to return products which are having low stock available in warehouse, w.r.t. reordering rule defined''' - ids = set() - ctx = self._context.copy() or {} - location = ctx.get('location', False) - location_condition = "" - if(location): - location_condition = "where location_id=%d"%(location) - else: - warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.company_id.id)]) - location_ids = [wh.lot_stock_id.id for wh in warehouse] - if len(location_ids) > 1: - location_condition = "where location_id in %s"%(tuple(location_ids)) - elif len(location_ids) == 1: - location_condition = "where location_id=%d"%(location_ids[0]) - self._cr.execute("select product_id from stock_warehouse_orderpoint " + location_condition) - product_ids = set(p_id[0] for p_id in self._cr.fetchall()) - for product in self.with_context({'context': ctx}).browse(list(product_ids)): - orderpoints = sorted(product.orderpoint_ids, key=lambda orderpoint: orderpoint.product_min_qty, reverse=True) - if (len(orderpoints) > 0 and product.virtual_available < orderpoints[0].product_min_qty): - ids.add(product.id) - if ids: - if operator == '=': - return [('id', 'in', list(ids))] - elif operator == '!=': - return [('id', 'not in', list(ids))] - - low_stock = fields.Boolean(compute=_check_low_stock, search=_search_low_stock, string="Low Stock") + low_stock = fields.Boolean(string="Low Stock") diff --git a/bahmni_purchase/views/purchase_views.xml b/bahmni_purchase/views/purchase_views.xml index a0597a2..6f19790 100644 --- a/bahmni_purchase/views/purchase_views.xml +++ b/bahmni_purchase/views/purchase_views.xml @@ -5,6 +5,10 @@ purchase.order + + + + diff --git a/bahmni_sale/__manifest__.py b/bahmni_sale/__manifest__.py index 382b786..932c2ed 100644 --- a/bahmni_sale/__manifest__.py +++ b/bahmni_sale/__manifest__.py @@ -20,8 +20,9 @@ 'views/village_master_view.xml', 'views/sale_order_views.xml', 'views/sale_config_settings.xml', - 'views/pos_view.xml', - 'views/menus.xml', + 'views/pos_view.xml', + 'report/report_discount_heads.xml', + 'report/sale_report.xml', 'views/account_invoice_view.xml'], 'demo': [], 'qweb': [], diff --git a/bahmni_sale/models/sale_order.py b/bahmni_sale/models/sale_order.py index 70e0304..ff217d9 100644 --- a/bahmni_sale/models/sale_order.py +++ b/bahmni_sale/models/sale_order.py @@ -95,6 +95,17 @@ def _total_receivable(self): else: receivable = 0.00 return receivable + + def total_discount_heads(self): + + + self._cr.execute("""select acc.code,acc.name,sum(sale.discount) from sale_order sale + left join account_account acc on (acc.id = sale.disc_acc_id) + where sale.disc_acc_id is not null + group by 1,2 + """) + total_discount_value = self._cr.fetchall() + return total_discount_value @api.depends('partner_id') def _get_partner_details(self): @@ -136,7 +147,6 @@ def _get_partner_details(self): def onchange_order_line(self): '''Calculate discount amount, when discount is entered in terms of %''' amount_total = self.amount_untaxed + self.amount_tax - print("Level one test") if self.discount_type == 'fixed': self.discount_percentage = self.discount/amount_total * 100 elif self.discount_type == 'percentage': @@ -145,7 +155,6 @@ def onchange_order_line(self): @api.onchange('discount', 'discount_percentage', 'discount_type', 'chargeable_amount') def onchange_discount(self): amount_total = self.amount_untaxed + self.amount_tax - print("Level two test") if self.chargeable_amount: if self.discount_type == 'none' and self.chargeable_amount: self.discount_type = 'fixed' @@ -215,6 +224,8 @@ def _prepare_invoice(self): 'disc_acc_id': self.disc_acc_id.id, 'discount': tot_discount, 'round_off_amount': self.round_off_amount, + 'order_id': self.id, + 'amount_total': self.amount_total, } return invoice_vals diff --git a/bahmni_sale/models/village_master.py b/bahmni_sale/models/village_master.py index 380a57a..9a8af95 100644 --- a/bahmni_sale/models/village_master.py +++ b/bahmni_sale/models/village_master.py @@ -104,4 +104,6 @@ def onchange_state_id(self): domain.update({'tehsil_id': [('id', 'in', tehsil_ids)]}) self.country_id = self.state_id.country_id.id domain = [('id', '=', self.state_id.country_id.id)] + else: + domain = [('id', '=', self.state_id.country_id.id)] return {'domain': {'country_id': domain}} diff --git a/bahmni_sale/report/report_discount_heads.xml b/bahmni_sale/report/report_discount_heads.xml new file mode 100644 index 0000000..6ab4ef3 --- /dev/null +++ b/bahmni_sale/report/report_discount_heads.xml @@ -0,0 +1,88 @@ + + + + + + + + diff --git a/bahmni_sale/report/sale_report.xml b/bahmni_sale/report/sale_report.xml new file mode 100644 index 0000000..63bb619 --- /dev/null +++ b/bahmni_sale/report/sale_report.xml @@ -0,0 +1,19 @@ + + + + + + + Discount Heads Summary + sale.order + qweb-pdf + bahmni_sale.report_discount_heads_summarized + bahmni_sale.report_discount_heads_summarized + (object._get_report_base_filename()) + ((object.name or 'INV').replace('/','_')+'.pdf') + + report + + + + diff --git a/bahmni_sale/views/sale_order_views.xml b/bahmni_sale/views/sale_order_views.xml index 9fb089d..77277df 100644 --- a/bahmni_sale/views/sale_order_views.xml +++ b/bahmni_sale/views/sale_order_views.xml @@ -12,6 +12,7 @@ + diff --git a/bahmni_stock/__manifest__.py b/bahmni_stock/__manifest__.py index be8fec7..f9ede11 100644 --- a/bahmni_stock/__manifest__.py +++ b/bahmni_stock/__manifest__.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- + { 'name': 'Bahmni Stock', 'version': '1.0', diff --git a/bahmni_stock/models/__init__.py b/bahmni_stock/models/__init__.py index 1a33421..cc02537 100644 --- a/bahmni_stock/models/__init__.py +++ b/bahmni_stock/models/__init__.py @@ -4,4 +4,3 @@ from . import stock_move from . import product from . import account_invoice_line -from . import account_payment \ No newline at end of file diff --git a/bahmni_stock/models/stock_move.py b/bahmni_stock/models/stock_move.py index 80f5c1f..52e5c96 100644 --- a/bahmni_stock/models/stock_move.py +++ b/bahmni_stock/models/stock_move.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- + from datetime import datetime from dateutil import tz @@ -8,23 +8,8 @@ class StockMove(models.Model): _inherit = 'stock.move' - @api.depends('picking_id') - def _get_picking_time(self): - for move in self: - from_zone = tz.gettz('UTC') - to_zone = tz.gettz(self._context.get('tz')) - if move.picking_id.date: - move_picking_date = '2023-10-11 14:30:00' - utc = datetime.strptime(move_picking_date, '%Y-%m-%d %H:%M:%S') - # Tell the datetime object that it's in UTC time zone since - # datetime objects are 'naive' by default - utc = utc.replace(tzinfo=from_zone) - # Convert time zone - central = utc.astimezone(to_zone) - move.stock_picking_time = datetime.strftime(central, DTF) - stock_picking_time = fields.Datetime(compute=_get_picking_time, - string="Stock Picking_time", store=True) + stock_picking_time = fields.Datetime(string="Stock Picking_time", store=True) @api.model def create(self,vals): if vals.get('origin'): diff --git a/bahmni_stock/models/stock_production_lot.py b/bahmni_stock/models/stock_production_lot.py index 7aff086..5cad61d 100644 --- a/bahmni_stock/models/stock_production_lot.py +++ b/bahmni_stock/models/stock_production_lot.py @@ -44,7 +44,6 @@ def _get_future_stock_forecast(self): context['location_id'] = 15 locations = self.env['stock.lot'].browse(context.get('location_id')) if locations[0]: - print("locations",type(locations)) self._cr.execute('''select lot_id, sum(quantity) @@ -55,7 +54,6 @@ def _get_future_stock_forecast(self): group by lot_id''', (tuple(locations.ids), lot.id,)) result = self._cr.dictfetchall() - print("result",result) if result and result[0]: lot.stock_forecast = result[0].get('sum') diff --git a/restful_api/controllers/token.py b/restful_api/controllers/token.py index 3a0147c..04d5896 100755 --- a/restful_api/controllers/token.py +++ b/restful_api/controllers/token.py @@ -35,8 +35,9 @@ def __init__(self): @http.route("/api/odoo-login", methods=["POST","OPTIONS"], type="json", auth="none", csrf=True, cors='*') def token(self, **post): try: - input_user_name = post.get("data").get("username"), - input_password = post.get("data").get("password") + json_data = json.loads(request.httprequest.data) + input_user_name = json_data.get("username"), + input_password = json_data.get("password") if input_user_name[0] != None and input_user_name[0] != None: res_usersss = request.env['res.users'].sudo().search([ ('active','=',True), diff --git a/restful_api/models/api_data_feed.py b/restful_api/models/api_data_feed.py index 5887a79..a77fc94 100644 --- a/restful_api/models/api_data_feed.py +++ b/restful_api/models/api_data_feed.py @@ -51,9 +51,10 @@ class RestFullService(http.Controller): @validate_token def bahmni_saleorder_creation(self, **kw): """ API Sale order creation from bahmin to Odoo """ + json_data = json.loads(request.httprequest.data) try: - if kw: - return {'status':200,'message': request.env['api.event.worker'].process_event(kw.get('data'))} + if json_data: + return {'status':200,'message': request.env['api.event.worker'].process_event(json_data)} except Exception as e: return { "status":417, @@ -64,9 +65,10 @@ def bahmni_saleorder_creation(self, **kw): @validate_token def bahmni_customer_feed(self, **kw): """ API customer feed from bahmin to Odoo """ + json_data = json.loads(request.httprequest.data) try: - if kw: - return {'status':200,'message': request.env['api.event.worker'].process_event(kw.get('data'))} + if json_data: + return {'status':200,'message': request.env['api.event.worker'].process_event(json_data)} except Exception as e: return { "status":417, @@ -77,9 +79,10 @@ def bahmni_customer_feed(self, **kw): @validate_token def bahmni_drug_feed(self, **kw): """ API Drug feed from bahmin to Odoo """ + json_data = json.loads(request.httprequest.data) try: - if kw: - return {'status':200,'message': request.env['api.event.worker'].process_event(kw.get('data'))} + if json_data: + return {'status':200,'message': request.env['api.event.worker'].process_event(json_data)} except Exception as e: return { "status":417, @@ -90,9 +93,10 @@ def bahmni_drug_feed(self, **kw): @validate_token def bahmni_rediology_test(self, **kw): """ Rediology test API """ + json_data = json.loads(request.httprequest.data) try: - if kw: - return {'status':200,'message': request.env['api.event.worker'].process_event(kw.get('data'))} + if json_data: + return {'status':200,'message': request.env['api.event.worker'].process_event(json_data)} except Exception as e: return { "status":417, @@ -103,9 +107,10 @@ def bahmni_rediology_test(self, **kw): @validate_token def bahmni_lab_test(self, **kw): """ Lab test API """ + json_data = json.loads(request.httprequest.data) try: - if kw: - return {'status':200,'message': request.env['api.event.worker'].process_event(kw.get('data'))} + if json_data: + return {'status':200,'message': request.env['api.event.worker'].process_event(json_data)} except Exception as e: return { "status":417, @@ -116,9 +121,10 @@ def bahmni_lab_test(self, **kw): @validate_token def bahmni_lab_panel(self, **kw): """ Lab Panel API """ + json_data = json.loads(request.httprequest.data) try: - if kw: - return {'status':200,'message': request.env['api.event.worker'].process_event(kw.get('data'))} + if json_data: + return {'status':200,'message': request.env['api.event.worker'].process_event(json_data)} except Exception as e: return { "status":417, @@ -129,9 +135,10 @@ def bahmni_lab_panel(self, **kw): @validate_token def bahmni_service_sale(self, **kw): """ Service Sale API """ + json_data = json.loads(request.httprequest.data) try: - if kw: - return {'status':200,'message': request.env['api.event.worker'].process_event(kw.get('data'))} + if json_data: + return {'status':200,'message': request.env['api.event.worker'].process_event(json_data)} except Exception as e: return { "status":417,