diff --git a/bahmni_customer_return/models/bahmni_customer_return.py b/bahmni_customer_return/models/bahmni_customer_return.py
index 48928cd..f95f230 100644
--- a/bahmni_customer_return/models/bahmni_customer_return.py
+++ b/bahmni_customer_return/models/bahmni_customer_return.py
@@ -24,7 +24,9 @@ class BahmniCustomerReturn(models.Model):
name = fields.Char(string="Return No")
entry_date = fields.Datetime('Entry Date',default=fields.Datetime.now)
- location_id = fields.Many2one('stock.location', 'Return Location',domain=[('active', '=', True),('usage', '=', 'internal')])
+ location_id = fields.Many2one('stock.location', 'Return Location',
+ default=lambda self: self.env['stock.picking.type'].search([('code', '=', 'incoming'),('sequence_code', '=', 'IN'),('barcode', '=', 'WH-RETURNS')], limit=1).default_location_dest_id.id,
+ domain=[('active', '=', True),('usage', '=', 'internal')])
customer_id = fields.Many2one('res.partner', 'Customer',domain=[('active', '=', True),('customer_rank', '>', 0)])
status = fields.Selection(selection=CUSTOM_STATUS, string="Status", copy=False, default="draft", readonly=True, store=True, tracking=True)
@@ -32,8 +34,10 @@ class BahmniCustomerReturn(models.Model):
company_id = fields.Many2one('res.company', copy=False, default=lambda self: self.env.company, ondelete='restrict', readonly=True, required=True)
currency_id = fields.Many2one('res.currency', string="Currency", copy=False, default=lambda self: self.env.company.currency_id.id, ondelete='restrict', readonly=True, tracking=True)
- tot_amt = fields.Float(string="Return Amount", store=True, compute='_compute_all_line')
- product_ids = fields.Many2many('product.product','customer_returns_products','return_id','product_id','Products',domain=[('active', '=', True),('type','=','product')])
+ tot_amt = fields.Float(string="Total Amount", store=True, compute='_compute_all_line')
+ discount_value = fields.Float(string="Dicount Amount", store=True, compute='_compute_all_line')
+ return_amt = fields.Float(string="Return Amount", store=True, compute='_compute_all_line')
+ product_ids = fields.Many2many('product.product','customer_returns_products','return_id','product_id','Products',domain=[('active', '=', True)])
active = fields.Boolean(string="Visible", default=True)
@@ -108,7 +112,16 @@ def onchange_product_ids(self):
@api.depends('line_ids')
def _compute_all_line(self):
for data in self:
- data.tot_amt = sum(line.sub_total for line in data.line_ids)
+ cumulative_discount_value = 0
+ for line in self.line_ids:
+ total_sale_value_with_tax = line.sale_order_id.amount_untaxed + line.sale_order_id.amount_tax
+ applied_discount_percentage = (line.sale_order_id.discount / total_sale_value_with_tax) * 100
+ line_discount_value = (line.sub_total * applied_discount_percentage) / 100
+ cumulative_discount_value += line_discount_value
+
+ data.discount_value = cumulative_discount_value
+ data.tot_amt = sum(line.sub_total for line in data.line_ids)
+ data.return_amt = (sum(line.sub_total for line in data.line_ids) - cumulative_discount_value )
def display_warnings(self, warning_msg, kw):
@@ -144,9 +157,133 @@ def validations(self, **kw):
return self.display_warnings(warning_msg, kw)
+ @api.model
+ def auto_return_stock(self):
+ """Automatically create a stock return picking."""
+
+ picking_vals = {
+ 'partner_id': self.customer_id.id, # Customer
+ 'picking_type_id': self.env['stock.picking.type'].search([('code', '=', 'incoming'),('sequence_code', '=', 'IN'),('barcode', '=', 'WH-RETURNS')], limit=1).id,
+ 'location_id': self.env['stock.location'].search([('usage', '=', 'customer')], limit=1).id,
+ 'location_dest_id': self.location_id.id,
+ 'move_type': 'direct',
+ 'scheduled_date': time.strftime(TIME_FORMAT),
+ }
+
+ return_picking = self.env['stock.picking'].create(picking_vals)
+
+ for order in self.line_ids:
+
+ # Create a stock.move entry
+ move = self.env['stock.move'].create({
+ 'name': order.product_id.name,
+ 'product_id': order.product_id.id,
+ 'product_uom_qty': order.qty,
+ 'product_uom': order.sale_order_line_id.product_uom.id,
+ 'picking_id': return_picking.id,
+ 'location_id': return_picking.location_id.id,
+ 'location_dest_id': return_picking.location_dest_id.id,
+ })
+
+ # Get the associated outgoing delivery picking
+ picking = order.sale_order_id.picking_ids.filtered(
+ lambda p: p.state == 'done' and p.picking_type_id.code == 'outgoing'
+ )
+ if not picking:
+ raise UserError("No completed delivery order found for this sale order.")
+
+ # Find the move line matching the given lot
+ if order.product_id.detailed_type =='product' and order.product_id.tracking == 'lot':
+ move_line = picking.move_line_ids.filtered(lambda ml: ml.lot_id.id == order.lot_id.id)
+ if not move_line:
+ raise UserError("The specified lot is not found in the delivery order.")
+ return_lot_id = order.lot_id.id
+ else:
+ return_lot_id = False
+
+ # Create a stock.move.line entry
+ move_line = self.env['stock.move.line'].create({
+ 'move_id': move.id,
+ 'picking_id': return_picking.id,
+ 'product_id': order.product_id.id,
+ 'product_uom_id': order.sale_order_line_id.product_uom.id,
+ 'qty_done': order.qty,
+ 'location_id': return_picking.location_id.id,
+ 'location_dest_id': return_picking.location_dest_id.id,
+ 'lot_id': return_lot_id,
+ })
+
+ ##validate picking
+ return_picking.with_context(validation_confirmed=True).button_validate()
+
+
+ @api.model
+ def create_partial_credit_note(self):
+
+ # Prepare line items for the credit note
+ line_items = []
+ cumulative_discount_value = 0.00
+ for line in self.line_ids:
+ invoice = line.sale_order_id.invoice_ids.filtered(lambda inv: inv.state == 'posted' and inv.move_type == 'out_invoice')
+
+ if not invoice:
+ raise ValueError(_("No valid invoice found for the selected Sale Order."))
+
+ line_items.append((0, 0, {
+ 'product_id': line.sale_order_line_id.product_id.id,
+ 'name': line.sale_order_line_id.product_id.display_name or 'Product',
+ 'quantity': line.qty,
+ 'price_unit': line.sale_order_line_id.price_unit,
+ 'account_id': line.sale_order_line_id.product_id.categ_id.property_account_income_categ_id.id or self.env['ir.property']._get('property_account_income_categ_id', 'product.category').id,
+ }))
+ if self.discount_value > 0:
+ line_items.append((0, 0, {
+ 'product_id': self.env['product.product'].search([('default_code', '=', 'DISC')], limit=1).id,
+ 'name': self.env['product.product'].search([('default_code', '=', 'DISC')], limit=1).display_name or 'Product',
+ 'quantity': 1,
+ 'price_unit': -abs(self.discount_value),
+ 'account_id': self.env['product.product'].search([('default_code', '=', 'DISC')], limit=1).categ_id.property_account_income_categ_id.id or self.env['ir.property']._get('property_account_income_categ_id', 'product.category').id,
+ }))
+
+ # Create the credit note
+ credit_note = self.env['account.move'].create({
+ 'move_type': 'out_refund',
+ 'partner_id': self.customer_id.id,
+ 'invoice_date': fields.Date.today(),
+ 'ref': self.name,
+ 'invoice_line_ids': line_items,
+ })
+
+ # Post the credit note
+ credit_note.action_post()
+
def entry_confirm(self):
if self.status in ('draft'):
self.validations()
+
+ for record in self.line_ids:
+ ### Return Entry Process Start here
+ # Search for existing return lines for the same sale order line
+ return_lines = self.env['bahmni.customer.return.line'].search([
+ ('sale_order_line_id', '=', record.sale_order_line_id.id)])
+
+ # Calculate the total return quantity for this sale order line
+ total_return_qty = sum(line.qty for line in return_lines)
+
+ # Minus the current record's quantity to the total qty
+ already_done_return_qty = total_return_qty - record.qty
+
+ # Validation: check if total return quantity exceeds the sale order quantity
+ if total_return_qty > record.sale_order_line_id.product_uom_qty:
+ raise UserError(f"Sale Order Ref {record.sale_order_id.name} - Already Return quantity {already_done_return_qty} for the product {record.sale_order_line_id.product_id.name} "
+ f"cannot exceed the total order quantity ({record.sale_order_line_id.product_uom_qty}).")
+ self.auto_return_stock()
+
+ ### Return Entry Process End
+
+ ### Credit Note Entry Process Start here
+ self.create_partial_credit_note()
+
self.name = self.env['ir.sequence'].next_by_code('bahmni.customer.return.sequence') or 'New'
self.write({'status': 'confirm',
'confirm_user_id': self.env.user.id,
diff --git a/bahmni_customer_return/views/bahmni_customer_return_views.xml b/bahmni_customer_return/views/bahmni_customer_return_views.xml
index dffef77..aa11ffa 100644
--- a/bahmni_customer_return/views/bahmni_customer_return_views.xml
+++ b/bahmni_customer_return/views/bahmni_customer_return_views.xml
@@ -52,7 +52,11 @@