Reference for #5 and #1

This commit is contained in:
Deena 2025-08-04 15:29:56 +05:30
parent de6c275785
commit e608da1fc9
15 changed files with 234 additions and 53 deletions

View File

@ -11,7 +11,7 @@
id="main_menu_dms" id="main_menu_dms"
name="Documents" name="Documents"
web_icon="dms,static/description/icon.png" web_icon="dms,static/description/icon.png"
groups="group_dms_user" groups="group_dms_user,sos_inventory.sos_marketing_user"
> >
<menuitem id="menu_dms_file" name="Files" sequence="20" action="action_dms_file" /> <menuitem id="menu_dms_file" name="Files" sequence="20" action="action_dms_file" />
<menuitem <menuitem

View File

@ -18,8 +18,7 @@
'security/security.xml', 'security/security.xml',
'security/record_rules.xml', 'security/record_rules.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
# 'data/cron_jobs.xml', 'data/cron_jobs.xml',
'views/sos_audit_log_view.xml', 'views/sos_audit_log_view.xml',
'views/menu.xml', 'views/menu.xml',
'views/sos_quote_generation.xml', 'views/sos_quote_generation.xml',
@ -81,6 +80,7 @@
'views/sos_master_customer_property.xml', 'views/sos_master_customer_property.xml',
'views/sos_service_call_log_report.xml', 'views/sos_service_call_log_report.xml',
'views/sos_transfer_challan_return_from_customer_view.xml', 'views/sos_transfer_challan_return_from_customer_view.xml',
'views/sos_shelflife_register_view.xml',
'wizard/sfg_bom_bulk_upload_view.xml', 'wizard/sfg_bom_bulk_upload_view.xml',
'wizard/mon_bulk_upload_view.xml', 'wizard/mon_bulk_upload_view.xml',
'wizard/missing_component_wizard.xml', 'wizard/missing_component_wizard.xml',
@ -93,7 +93,6 @@
'wizard/stock_movement_report_wizard.xml', 'wizard/stock_movement_report_wizard.xml',
'wizard/dock_audit_report.xml', 'wizard/dock_audit_report.xml',
'wizard/material_backup_export.xml', 'wizard/material_backup_export.xml',
'report/view_quote.xml', 'report/view_quote.xml',
'report/sos_po_report.xml', 'report/sos_po_report.xml',
'report/sos_iqi_report.xml', 'report/sos_iqi_report.xml',
@ -114,6 +113,7 @@
'report/sos_dock_audit_report.xml', 'report/sos_dock_audit_report.xml',
'report/mme_history_card_report.xml', 'report/mme_history_card_report.xml',
'report/sos_boq_labels.xml', 'report/sos_boq_labels.xml',
'report/shelflife_report.xml',
'data/send_indent_plan_email_template.xml', 'data/send_indent_plan_email_template.xml',
'data/selection_item.xml' 'data/selection_item.xml'

View File

@ -1,16 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo> <odoo>
<data noupdate="1"> <record id="action_weekly_shelflife_report" model="ir.cron">
<record id="cron_test_material_backup" model="ir.cron"> <field name="name">Weekly Shelf Life Expiry Report</field>
<field name="name">[TEST] Material Table Backup Every Minute</field> <field name="model_id" ref="model_sos_shelflife_register"/>
<field name="active" eval="True"/> <field name="state">code</field>
<field name="priority">10</field> <field name="code">model.action_generate_expiry_report()</field>
<field name="interval_number">1</field> <field name="interval_number">1</field>
<field name="interval_type">minutes</field> <field name="interval_type">weeks</field>
<field name="numbercall">-1</field> <field name="numbercall">-1</field>
<field name="nextcall">2026-03-31 23:59:00</field> <field name="nextcall">2025-08-11 08:00:00</field>
<field name="model_id" ref="model_sos_material"/> <field name="doall">True</field>
<field name="state">code</field> </record>
<field name="code">model.cron_create_table_backup()</field> </odoo>
</record>
</data>
</odoo>

View File

@ -57,4 +57,5 @@ from . import sos_inventory_customers
from . import sos_master_customer_property from . import sos_master_customer_property
from . import sos_service_call_log_report from . import sos_service_call_log_report
from . import sos_inhouse_validation_reports_files from . import sos_inhouse_validation_reports_files
from . import sos_transfer_challan_return_from_customer from . import sos_transfer_challan_return_from_customer
from . import sos_shelflife_register

View File

@ -42,7 +42,7 @@ class SOS_IR(models.Model):
('SFG', 'SFG'), ('SFG', 'SFG'),
('FG', 'FG') ('FG', 'FG')
], string='Goods Type',default="Materials",copy=True) ], string='Goods Type',default="Materials",copy=True)
line_ids_material = fields.One2many('sos_ir_line_material', 'ir_id', string="Components for Materials",copy=True) line_ids_material = fields.One2many('sos_ir_line_material', 'ir_id', string="Materials Lines",copy=True)
vehicle_type = fields.Selection([ vehicle_type = fields.Selection([
('yes', 'Yes'), ('yes', 'Yes'),
('no', 'No'), ('no', 'No'),
@ -217,7 +217,14 @@ class SOS_IR(models.Model):
for item in self.line_ids_material: for item in self.line_ids_material:
# Fetch the component related to the current item # Fetch the component related to the current item
component = self.env['sos_material'].browse(item.component_id.id) component = self.env['sos_material'].browse(item.component_id.id)
#print(component) if component.shelf_life == "yes":
shelflife_line_values = {
'ir_ref_no':self.id,
'name': item.component_id.id, # Reference the created GRN
'quantity': item.qty,
'expiry_date':item.expiry_date
}
shellife_record = self.env['sos_shelflife_register'].create(shelflife_line_values)
#raise UserError("The PO Number already exists. Validation failed.") #raise UserError("The PO Number already exists. Validation failed.")
if self.po_no: if self.po_no:
for pos in self.po_no.line_ids: for pos in self.po_no.line_ids:
@ -410,10 +417,13 @@ class SOS_IR_Line_Material(models.Model):
test_report = fields.Binary(string="Test Report") test_report = fields.Binary(string="Test Report")
test_report_filename=fields.Char(string="Test Report File Name") test_report_filename=fields.Char(string="Test Report File Name")
expiry_date = fields.Date(string="Expiry Date") expiry_date = fields.Date(string="Expiry Date")
shelf_life = fields.Selection([('yes', 'Yes'), ('no', 'No')],related="component_id.shelf_life", string="Shelf Life")
@api.onchange('component_id') @api.onchange('component_id')
def _onchange_component_id(self): def _onchange_component_id(self):
if self.component_id: if self.component_id:
self.unit_price = self.component_id.unit_price self.unit_price = self.component_id.unit_price
def action_view_pdf(self): def action_view_pdf(self):
"""Action to view the PDF of the test report.""" """Action to view the PDF of the test report."""

View File

@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
from datetime import date
import base64
class SOS_Shelflife_Material_Register(models.Model):
_name = 'sos_shelflife_register'
_description = 'Shelf Life Register'
name = fields.Many2one('sos_material',string="Material Name", required=True)
quantity = fields.Float(string="Quantity")
expiry_date = fields.Date(string="Expiry Date")
ir_ref_no = fields.Many2one('sos_ir',string="Inward Ref No")
remaining_days = fields.Integer(string="Remaining days to expire", compute="_compute_remaining_days", store=True)
@api.depends('expiry_date')
def _compute_remaining_days(self):
today = date.today()
for record in self:
if record.expiry_date:
delta = (record.expiry_date - today).days
record.remaining_days = max(0, delta) # don't show negative days
else:
record.remaining_days = 0
def action_generate_expiry_report(self):
expiring_materials = self.search([
('remaining_days', '<', 7),
('remaining_days', '>', 0)
])
if not expiring_materials:
return
# Build HTML table
table_rows = ''.join([
f"""
<tr>
<td>{material.name.part_no or ''}</td>
<td>{material.expiry_date or ''}</td>
<td>{material.remaining_days or ''}</td>
</tr>
"""
for material in expiring_materials
])
html_body = f"""
<p>Dear Team,</p>
<p>Below is the weekly report of materials expiring within 7 days:</p>
<table class="table" border="1" cellpadding="5" cellspacing="0" style="border-collapse: collapse;">
<thead>
<tr>
<th>Material Name</th>
<th>Expiry Date</th>
<th>Remaining Days to Expire</th>
</tr>
</thead>
<tbody>
{table_rows}
</tbody>
</table><br></br>
<p>Regards,<br/>Slink Admin</p>
"""
# Get users in the group
group = self.env.ref('sos_inventory.sos_scg_group_user')
users = self.env['res.users'].search([('groups_id', 'in', group.id)])
recipient_emails = ','.join(filter(None, users.mapped('email')))
# Create and send the email directly
mail_template = self.env['mail.template'].create({
'name': 'HTML Shelf Life Expiry Report',
'model_id': self.env['ir.model']._get(self._name).id,
'subject': f'Shelf Life Expiry Report - {date.today().strftime("%Y-%m-%d")}',
'email_from': self.env.user.email,
'email_to': recipient_emails,
'body_html': html_body,
})
mail_template.send_mail(
res_id=expiring_materials[0].id, # Just link to one of the records
force_send=True
)

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<template id="report_shelflife_expiry">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<div class="page">
<h2>Materials Expiring Within 7 Days</h2>
<p>Report generated on: <span t-field="docs[0].write_date" t-options='{"format": "MM/dd/YYYY"}'/></p>
<table class="table table-condensed">
<thead>
<tr>
<th>Material Name</th>
<th>Quantity</th>
<th>Expiry Date</th>
<th>Remaining Days</th>
</tr>
</thead>
<tbody>
<t t-foreach="docs" t-as="record">
<tr>
<td><span t-field="record.name"/></td>
<td><span t-field="record.quantity"/></td>
<td><span t-field="record.expiry_date"/></td>
<td><span t-field="record.remaining_days"/></td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
</t>
</template>
<record id="action_shelflife_expiry_report" model="ir.actions.report">
<field name="name">Shelf Life Expiry Report</field>
<field name="model">sos_shelflife_register</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">sos_inventory.report_shelflife_expiry</field>
<field name="report_file">sos_shelflife_expiry_report</field>
</record>
</odoo>

View File

@ -195,5 +195,6 @@ access_ncmr_report_wizard,ncmr_report_wizard access,model_ncmr_report_wizard,bas
access_sos_parameter_fir,sos_parameter_fir access,model_sos_parameter_fir,base.group_user,1,1,1,1 access_sos_parameter_fir,sos_parameter_fir access,model_sos_parameter_fir,base.group_user,1,1,1,1
access_sos_transfer_challan_return_from_customer_lines,sos_transfer_challan_return_from_customer_lines access,model_sos_transfer_challan_return_from_customer_lines,base.group_user,1,1,1,1 access_sos_transfer_challan_return_from_customer_lines,sos_transfer_challan_return_from_customer_lines access,model_sos_transfer_challan_return_from_customer_lines,base.group_user,1,1,1,1
access_sos_transfer_challan_return_from_customer,sos_transfer_challan_return_from_customer access,model_sos_transfer_challan_return_from_customer,base.group_user,1,1,1,1 access_sos_transfer_challan_return_from_customer,sos_transfer_challan_return_from_customer access,model_sos_transfer_challan_return_from_customer,base.group_user,1,1,1,1
access_sos_shelflife_register,sos_shelflife_register access,model_sos_shelflife_register,base.group_user,1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
195 access_sos_parameter_fir sos_parameter_fir access model_sos_parameter_fir base.group_user 1 1 1 1
196 access_sos_transfer_challan_return_from_customer_lines sos_transfer_challan_return_from_customer_lines access model_sos_transfer_challan_return_from_customer_lines base.group_user 1 1 1 1
197 access_sos_transfer_challan_return_from_customer sos_transfer_challan_return_from_customer access model_sos_transfer_challan_return_from_customer base.group_user 1 1 1 1
198 access_sos_shelflife_register sos_shelflife_register access model_sos_shelflife_register base.group_user 1 1 1 1
199
200

View File

@ -99,7 +99,8 @@
<field name="order_qty"/> <field name="order_qty"/>
<field name="qty"/> <field name="qty"/>
<field name="unit_price"/> <field name="unit_price"/>
<field name="expiry_date"/> <field name="shelf_life" column_invisible="1"/>
<field name="expiry_date" required="shelf_life == 'yes'"/>
<field name="test_report" widget="binary" filename="test_report_filename"/> <field name="test_report" widget="binary" filename="test_report_filename"/>
<field name="test_report_filename" column_invisible="1"/> <field name="test_report_filename" column_invisible="1"/>
<button name="action_view_pdf" invisible="not test_report" type="object" string="View" class="btn-primary" icon="fa-eye"/> <button name="action_view_pdf" invisible="not test_report" type="object" string="View" class="btn-primary" icon="fa-eye"/>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="view_sos_shelflife_register_tree" model="ir.ui.view">
<field name="name">sos_shelflife_register.tree</field>
<field name="model">sos_shelflife_register</field>
<field name="arch" type="xml">
<tree string="Register">
<field name="name"/>
<field name="quantity"/>
<field name="expiry_date"/>
<field name="ir_ref_no"/>
<field name="remaining_days" decoration-danger="remaining_days &lt; 7" decoration-success="remaining_days &gt;= 7"/> <field name="write_uid" string="Last Edited By" optional="hide"/>
<field name="write_date" string="Last Edited On" optional="hide"/>
</tree>
</field>
</record>
<record id="view_sos_shelflife_register_form" model="ir.ui.view">
<field name="name">sos_shelflife_register.form</field>
<field name="model">sos_shelflife_register</field>
<field name="arch" type="xml">
<form string="Calibration Device">
<sheet>
<group>
<field name="ir_ref_no" readonly="1"/>
<field name="name"/>
<field name="quantity"/>
</group>
<group>
<field name="expiry_date"/>
<field name="remaining_days" decoration-danger="remaining_days &lt; 7" decoration-success="remaining_days &gt;= 7"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_sos_shelflife_register" model="ir.actions.act_window">
<field name="name">Shelf Life Register</field>
<field name="res_model">sos_shelflife_register</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_sos_shelflife_register_tree"/>
</record>
<menuitem id="menu_sos_shelflife_register" name="Material Shelf Life Register"
parent="scg_forms_menu_root" action="action_sos_shelflife_register" groups="sos_inventory.sos_qc_user,sos_inventory.sos_qa_user,sos_inventory.sos_management_user,sos_inventory.sos_scg_group_user"/>
</odoo>

View File

@ -96,7 +96,7 @@ class SOS_Sales_Achievement_Report(models.Model):
achievement_percentage_total = fields.Char(string="Achievement Percentage For Total", compute="_compute_achievement_percentage_total", store=True) achievement_percentage_total = fields.Char(string="Achievement Percentage For Total", compute="_compute_achievement_percentage_total", store=True)
billed_target_total = fields.Char(string="Billed For Total", compute="_compute_billed_total_target", store=True) billed_target_total = fields.Char(string="Billed For Total", compute="_compute_billed_total_target", store=True)
yet_to_billed_target_total = fields.Char(string="Billed For Total", compute="_compute_yet_to_billed_total_target", store=True) yet_to_billed_target_total = fields.Char(string="Billed For Total", compute="_compute_yet_to_billed_total_target", store=True)
collected_target_total = fields.Char(string="collected For Total", compute="_compute_collected_total_target", store=True) collected_target_total = fields.Float(string="collected For Total", compute="_compute_collected_total_target", store=True)
can_edit_billed_target = fields.Boolean( can_edit_billed_target = fields.Boolean(
string="Can Edit Billed Target", string="Can Edit Billed Target",
compute="_compute_can_edit_billed_target", compute="_compute_can_edit_billed_target",
@ -451,20 +451,21 @@ class SOS_Sales_Achievement_Report(models.Model):
) )
def _compute_collected_total_target(self): def _compute_collected_total_target(self):
for record in self: for record in self:
record.collected_target_total = sum([ record.collected_target_total = round(sum([
record.collected_target_april or 0, record.collected_target_april or 0,
record.collected_target_may or 0, record.collected_target_may or 0,
record.collected_target_june or 0, record.collected_target_june or 0,
record.collected_target_july or 0, record.collected_target_july or 0,
record.collected_target_august or 0, record.collected_target_august or 0,
record.collected_target_september or 0, record.collected_target_september or 0,
record.collected_target_october or 0, record.collected_target_october or 0,
record.collected_target_november or 0, record.collected_target_november or 0,
record.collected_target_december or 0, record.collected_target_december or 0,
record.collected_target_january or 0, record.collected_target_january or 0,
record.collected_target_february or 0, record.collected_target_february or 0,
record.collected_target_march or 0 record.collected_target_march or 0
]) ]), 2)
@api.depends( @api.depends(
'billed_target_april','billed_target_may','billed_target_june', 'billed_target_april','billed_target_may','billed_target_june',
'billed_target_july','billed_target_august','billed_target_september', 'billed_target_july','billed_target_august','billed_target_september',
@ -473,7 +474,7 @@ class SOS_Sales_Achievement_Report(models.Model):
) )
def _compute_billed_total_target(self): def _compute_billed_total_target(self):
for record in self: for record in self:
record.billed_target_total = sum([ record.billed_target_total = round(sum([
record.billed_target_april or 0, record.billed_target_april or 0,
record.billed_target_may or 0, record.billed_target_may or 0,
record.billed_target_june or 0, record.billed_target_june or 0,
@ -486,7 +487,7 @@ class SOS_Sales_Achievement_Report(models.Model):
record.billed_target_january or 0, record.billed_target_january or 0,
record.billed_target_february or 0, record.billed_target_february or 0,
record.billed_target_march or 0 record.billed_target_march or 0
]) ]), 2)
@api.depends('actual_target_total', 'planned_target_total') @api.depends('actual_target_total', 'planned_target_total')
def _compute_achievement_percentage_total(self): def _compute_achievement_percentage_total(self):
for record in self: for record in self:
@ -503,7 +504,7 @@ class SOS_Sales_Achievement_Report(models.Model):
) )
def _compute_yet_to_billed_total_target(self): def _compute_yet_to_billed_total_target(self):
for record in self: for record in self:
record.yet_to_billed_target_total = sum([ record.yet_to_billed_target_total = round(sum([
record.yet_to_billed_target_april or 0, record.yet_to_billed_target_april or 0,
record.yet_to_billed_target_may or 0, record.yet_to_billed_target_may or 0,
record.yet_to_billed_target_june or 0, record.yet_to_billed_target_june or 0,
@ -516,7 +517,7 @@ class SOS_Sales_Achievement_Report(models.Model):
record.yet_to_billed_target_january or 0, record.yet_to_billed_target_january or 0,
record.yet_to_billed_target_february or 0, record.yet_to_billed_target_february or 0,
record.yet_to_billed_target_march or 0 record.yet_to_billed_target_march or 0
]) ]), 2)
@api.depends( @api.depends(
'planned_target_april','planned_target_may','planned_target_june', 'planned_target_april','planned_target_may','planned_target_june',
'planned_target_july','planned_target_august','planned_target_september', 'planned_target_july','planned_target_august','planned_target_september',
@ -740,15 +741,15 @@ class SOS_Sales_Achievement_Report_Brief(models.Model):
current_val = getattr(report, actual_field) or 0.0 current_val = getattr(report, actual_field) or 0.0
report.write({actual_field: current_val + value}) report.write({actual_field: current_val + value})
if billed_date: if billed_date:
self.env['sos_billing_collection'].create({ self.env['sos_billing_collection'].create({
'ref_id': report.id, 'ref_id': report.id,
'customer_name': customer_name, 'customer_name': customer_name,
'sales_person': report.sales_person.id, 'sales_person': report.sales_person.id,
'action_status': 'Billed', 'action_status': 'Billed',
'date_of_action': billed_date, 'date_of_action': billed_date,
'value': billed_value 'value': billed_value
}) })
new_record = super(SOS_Sales_Achievement_Report_Brief, self).create(vals) new_record = super(SOS_Sales_Achievement_Report_Brief, self).create(vals)
return new_record return new_record

View File

@ -92,7 +92,7 @@
<field name="value"/> <field name="value"/>
<field name="products"/> <field name="products"/>
<field name="po_no"/> <field name="po_no"/>
<field name="quantity"/> <!-- <field name="quantity"/> -->
</group> </group>
</sheet> </sheet>
</form> </form>
@ -139,7 +139,7 @@
<field name="value"/> <field name="value"/>
<field name="products"/> <field name="products"/>
<field name="po_no"/> <field name="po_no"/>
<field name="quantity"/> <!-- <field name="quantity"/> -->
</tree> </tree>
</field> </field>
<footer> <footer>