From e608da1fc9b36ae3c6171747511d12c58b14f625 Mon Sep 17 00:00:00 2001 From: Deena Date: Mon, 4 Aug 2025 15:29:56 +0530 Subject: [PATCH] Reference for #5 and #1 --- dms/views/menu.xml | 2 +- sos_inventory/__manifest__.py | 6 +- sos_inventory/data/cron_jobs.xml | 28 +++--- sos_inventory/models/__init__.py | 3 +- .../__pycache__/__init__.cpython-310.pyc | Bin 2526 -> 2571 bytes .../models/__pycache__/sos_ir.cpython-310.pyc | Bin 13012 -> 13263 bytes sos_inventory/models/sos_ir.py | 14 ++- .../models/sos_shelflife_register.py | 83 ++++++++++++++++++ sos_inventory/report/shelflife_report.xml | 41 +++++++++ sos_inventory/security/ir.model.access.csv | 1 + sos_inventory/views/sos_ir_view.xml | 3 +- .../views/sos_shelflife_register_view.xml | 45 ++++++++++ ...s_sales_achievement_report.cpython-310.pyc | Bin 26093 -> 26278 bytes .../models/sos_sales_achievement_report.py | 57 ++++++------ .../sos_sales_achievement_wizard_view.xml | 4 +- 15 files changed, 234 insertions(+), 53 deletions(-) create mode 100755 sos_inventory/models/sos_shelflife_register.py create mode 100644 sos_inventory/report/shelflife_report.xml create mode 100755 sos_inventory/views/sos_shelflife_register_view.xml diff --git a/dms/views/menu.xml b/dms/views/menu.xml index f74778f..e8071c5 100755 --- a/dms/views/menu.xml +++ b/dms/views/menu.xml @@ -11,7 +11,7 @@ id="main_menu_dms" name="Documents" web_icon="dms,static/description/icon.png" - groups="group_dms_user" + groups="group_dms_user,sos_inventory.sos_marketing_user" > - - - [TEST] Material Table Backup Every Minute - - 10 - 1 - minutes - -1 - 2026-03-31 23:59:00 - - code - model.cron_create_table_backup() - - - + + Weekly Shelf Life Expiry Report + + code + model.action_generate_expiry_report() + 1 + weeks + -1 + 2025-08-11 08:00:00 + True + + \ No newline at end of file diff --git a/sos_inventory/models/__init__.py b/sos_inventory/models/__init__.py index fa11e2f..3537e14 100755 --- a/sos_inventory/models/__init__.py +++ b/sos_inventory/models/__init__.py @@ -57,4 +57,5 @@ from . import sos_inventory_customers from . import sos_master_customer_property from . import sos_service_call_log_report from . import sos_inhouse_validation_reports_files -from . import sos_transfer_challan_return_from_customer \ No newline at end of file +from . import sos_transfer_challan_return_from_customer +from . import sos_shelflife_register \ No newline at end of file diff --git a/sos_inventory/models/__pycache__/__init__.cpython-310.pyc b/sos_inventory/models/__pycache__/__init__.cpython-310.pyc index 95c81f28ab2dcd36bd6eb0b6c781d00049437179..e4b259808be200444ddc747200f029fe9e7970f3 100644 GIT binary patch delta 120 zcmca7+%3YJ&&$ij00i;Q6EYS}Vm!uZ?Y1(eS%dW}DS7Zw`Z6!mIJ&-E0pUlr0 U%2EMjPA=fgncTq1#U#K807J?lxc~qF delta 70 zcmeAcxhKq<&&$ij00coART;Gtd1V<-Y}7u%#A*}FplQ3Ah4~Q+v!ABTW@ZjeM$VNC YMRq`yMRt>|I71oBCQsljXA)op0AWWE)&Kwi diff --git a/sos_inventory/models/__pycache__/sos_ir.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_ir.cpython-310.pyc index 58cde96c6cb39f1f4754ef2ce6e8efc9dccacb32..1310398db536acf9f77ff15f8cb41ef9d9948a83 100644 GIT binary patch delta 3702 zcmbtXYiwLc6~41?@5B4>K5WO{hrNER<5%pK(2^3FSaDp^6k;c(Zqn<`&b58l-d$(z zI*!BLZrg;CRHSt>Ql-+M#w9d$+O#D3QHl^1AOaF9ErK@EEmhOuQ_3qfY>a|v~eBpL$t0~n8+LXyK zk8B=d(TZ#WF$UrR=TM@qDD9Q^6H?Zia z`vO7<;Q@p)z_NvTP<{~MA%utdmChi4I^g8B!Q93}sQMBBkRL($X2{tiJl$EtF9jRP zVSY9ECfUk=5=w^9dCDyO8n$$%s21|z6)hv-(_r&zxKLdSHZ|~Uf=AoTH$-;T^-!tg zfTwCwDmmeC=~C7_DDA$=&qX3-Pu5Od(*opkEe zOQht5wu?Q7m~{iorjk$hz!)En1fJ6{(g7{cw3QvC)w)lvu4rU2(jsMj)Vp3XNwRM* z)!pT+gZic|>=X>~qG3dWAztbg15sC@`uYkLxV@f&`p^=nJXt^WLjZr$tF)i$b}=0( z8_3$I6XY5Zu#E;z*h+rg!G5SaAZR}=+c!wMDI26UG2na?;&;vZya<&#ioIc4cft!{IcR+;09uJ!>ZDSQUURZRvH#O3oJ;9`Y;+0LN?^hgtIJoWk%JG+fI5 zS(Pow6iAFPdeEknnTZ*7LXnv=scOLefe8uzeOP~hcS*{|oby1K2h^oY*)AoOr2EoY@YwP;l+FKLaU@t zo0w!>&`NnQKN35Q@EpPj!ZHG~vYh~i1I*=2fhz0;)SX3m5dj^sm-uUq9aVT8{gvFo zK6O62lZOjG4f5jWHU zY<>~p8UD3c8SZ(tI0b>`i^~2Y8%9fUL5k^|!RGS__w%c`;+< znyHvR$=`^Nw1uv%9bBXGzVyr-d@6WRy|SV*1x9&Of}7lgznqBroWx?X5exj={_eBc zO#D(pGr!~>;deECM83@jo8x4WE6uy^zyuq94Hkw>RiwRqN*M1=o&m?g;vYJazD(oHXvVBI) zr`ZCN(RdtTJ%U&d{d}N(V~>jMBEmt0FC#pP@Hm1C;cbM=2)~l}m97ZC*nZxca(kJb z4|F$}H51|E-2?oc)bW06)bkam)G)@yo&0`Hpxhs9f3_n_-UjL|?7b4B|0(v`)Uz+sJ#movt8pn4H9IWoE)3NUh-ywj!LvCfs4tD02WF2wk7$)sxkUwl0Jq4)CDlMyN*cBKY{$b&WS9xYikfu8Y_` z$6xPhAHVsmit|k*t_EpD;zSBX_A2SZkj4>2KCB@ye1#W#n@u4x`#Kf`O)6qkkK8>X z4{w*Z;%NuJn>zSwz0I-fGh*2AR)r0^niTF`SC{<1=6|^||0mY9(VL#XVP7r5P36EF j0iQodzhQ(3-_p0qh3kZ2a-f~)i}163O;%5!JzW1U_Y$?k delta 3387 zcmbtWYj9gf6}~IUS8v&pCCd*M}q)v7wGe7{lw6smjBQ+EzbS8f~11)42NO)Ze!($lekHD{HrY%!AXJtE& zfgc$(bH97`oU`9Kd(Pcm{cPfz;?uoemju7L@0>jH?7oY>&I*!T`fx>?B^d#2(qdXi zwryw8vTOk{hR&|-x=!=)-LpA`Mfg+pJ^sdJ?^z{pTK6mYtgzwA6lLOkd? zOF~P}yQqakxyL&|)-MfuZB{bIcT~m6*pgnggS6Z)I2eH!+kk*l(#E!;`~bo>{zrc| z$@9uUe`psfgeiwo0bw8C8|Wnu@XrSr8RqW?o;!$~WyUQi%>X1_Y#8N75bj`^Mcp2R zIfO?M41gDH%!_gn;nN5u0Dd~qz-xoq&5xtzGXTK-B+7Tg&7R<|2Ybn9`8&a1l0p8H zP-_U|Caof*DW}H^s;;pTx7Az%`{f$lR|EEHcyLYmARh>i)zwg`=zzyLAr)QlxD6>| z-6|b?i(d?fOH#(po(7FQ;{e^3qR;SVWW$%K$jFlxcG~b{oG@}tR$1Q*(9n-Nk8_8TUwbh}z~ zDS=)3pG|6CX%eg!YgKNh4N^@Q5>3($+PP>W5?%XWS-K1vXLdZcR@&rs7k zI6Sz`lt&ef>MU7VPNQ-qwUnO2)5vt?4^J%1BBJRylrD@P!3gIC%Z#37d-?UqJ=Gt> zaXFmM)CpB%1%6NTTYK?RG3~f+;9?yxN_s^!wg@tN24N?{*AbAFjR2Sq3_Y$>g?$5c z&m+8mfPvVH{JvO+6R(8#$R>90k`@~!sdhGqwx5aa#LwdQ)nt(DBo1;`8VT{dU3Icg1n4u_<698 zBV6QviMNs(?r2)uFpn{OtKG^%nWoCF=lD?52!FHbtmOlVKhzwv$X0%`Id6T{^B}jh z+#uiO@3zFrDPG??wh60c`bC0NWw6@i46&^2GC;DTd>{T49qsv!vc1z?+BbAepo_qAQrkK*$FHL`c4bQ@+p5#7FMm52EQDQKrhRDQ^JBkfyB5rnOnoZ*~CP zu?gi$yQfr5NvSlSg3s?2zQ4WMza&^xjVf9JKjq)>lkF|;-{O?l5U%n|?e)#q&`bWP zs-@X18$C|DY3AJ> zO_qO1e7NK4hR8ycMi&W<(Z=J_6XZaQ#%a@W=|CfGhBKta42}$qqy~4T9>leLa{2sV zajthJ$!Y$@&KTkR2c7HTFWB|YuSL2sR1d(MYmcTD;yW3f3al5kef)*BAF^zf_~X6R zysfKC7Jsb@TwfRFxvpCB75-G$9`^*g9zn>WY)z5#4IGM{ z_6|yGZ}#HvFgD%Fv7E|g#dc#h^mrG+feAbLnf|bwy$6aDFwS>ycTd9UATHvuftGLT zd7ZRzOKUjSgnuEtgzy2tZuW1$xzMd{J(}Q>k(dP`h!fy;fEplF zAjk-I{#bAHj*8a0oM3tl&5Xa<+y3xf7nF&^L6ppmG@@jpc%p8iP&ex&${;fzcz&Df zeJ#Yt2YMnF=H(arYDj|rxUXgG_5zqPp4hNsZmB`=wi>LQ&i_{lepN2PnRN+z*CjCR nD=FMn8LC(n1bqVoS0YsLE&W^E_=Sl2!1zr6#tJ#Grl$TsoP%8n diff --git a/sos_inventory/models/sos_ir.py b/sos_inventory/models/sos_ir.py index 005e1aa..ed8d164 100755 --- a/sos_inventory/models/sos_ir.py +++ b/sos_inventory/models/sos_ir.py @@ -42,7 +42,7 @@ class SOS_IR(models.Model): ('SFG', 'SFG'), ('FG', 'FG') ], 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([ ('yes', 'Yes'), ('no', 'No'), @@ -217,7 +217,14 @@ class SOS_IR(models.Model): for item in self.line_ids_material: # Fetch the component related to the current item 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.") if self.po_no: 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_filename=fields.Char(string="Test Report File Name") 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') def _onchange_component_id(self): if self.component_id: self.unit_price = self.component_id.unit_price + def action_view_pdf(self): """Action to view the PDF of the test report.""" diff --git a/sos_inventory/models/sos_shelflife_register.py b/sos_inventory/models/sos_shelflife_register.py new file mode 100755 index 0000000..849f546 --- /dev/null +++ b/sos_inventory/models/sos_shelflife_register.py @@ -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""" + + {material.name.part_no or ''} + {material.expiry_date or ''} + {material.remaining_days or ''} + + """ + for material in expiring_materials + ]) + + html_body = f""" +

Dear Team,

+

Below is the weekly report of materials expiring within 7 days:

+ + + + + + + + + + {table_rows} + +
Material NameExpiry DateRemaining Days to Expire


+

Regards,
Slink Admin

+ """ + + # 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 + ) + \ No newline at end of file diff --git a/sos_inventory/report/shelflife_report.xml b/sos_inventory/report/shelflife_report.xml new file mode 100644 index 0000000..ff41ca8 --- /dev/null +++ b/sos_inventory/report/shelflife_report.xml @@ -0,0 +1,41 @@ + + + + + + Shelf Life Expiry Report + sos_shelflife_register + qweb-pdf + sos_inventory.report_shelflife_expiry + sos_shelflife_expiry_report + + \ No newline at end of file diff --git a/sos_inventory/security/ir.model.access.csv b/sos_inventory/security/ir.model.access.csv index d6e7c17..f5dd6d4 100755 --- a/sos_inventory/security/ir.model.access.csv +++ b/sos_inventory/security/ir.model.access.csv @@ -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_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_shelflife_register,sos_shelflife_register access,model_sos_shelflife_register,base.group_user,1,1,1,1 diff --git a/sos_inventory/views/sos_ir_view.xml b/sos_inventory/views/sos_ir_view.xml index dd9cc2b..a6e0773 100755 --- a/sos_inventory/views/sos_ir_view.xml +++ b/sos_inventory/views/sos_ir_view.xml @@ -99,7 +99,8 @@ - + +