From 5c1f60b3b8bdeeee64b7843883d2a6a96bd0a03d Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Sat, 30 May 2026 20:59:59 -0400 Subject: [PATCH] changes --- .DS_Store | Bin 26628 -> 28676 bytes .../__pycache__/clock_kiosk.cpython-312.pyc | Bin 8346 -> 8656 bytes .../clock_nfc_kiosk.cpython-312.pyc | Bin 13248 -> 21250 bytes .../__pycache__/hr_attendance.cpython-312.pyc | Bin 28154 -> 30528 bytes .../res_config_settings.cpython-312.pyc | Bin 12433 -> 12837 bytes fusion_inventory/__manifest__.py | 2 +- fusion_inventory/models/sync_config.py | 22 ++++++-- fusion_login_audit/__manifest__.py | 2 +- .../models/fusion_login_audit.py | 11 ++++ fusion_login_audit/models/res_users.py | 8 ++- fusion_login_audit/tests/test_login_audit.py | 2 + .../views/fusion_login_audit_views.xml | 14 ++++- .../__manifest__.py | 4 +- .../views/fp_express_order_views.xml | 44 +++++---------- .../wizard/fp_direct_order_wizard.py | 39 ++++++++++++- fusion_tasks/__manifest__.py | 2 +- fusion_tasks/models/task_sync.py | 53 ++++++++++++++---- 17 files changed, 147 insertions(+), 56 deletions(-) diff --git a/.DS_Store b/.DS_Store index 3ed1ee65c92e01051639277c60accb1a3202317d..857b631db623ec3211d468a678235e21e640e7d7 100644 GIT binary patch delta 425 zcmZp~!R&H~r zT`?o0_~iZea+7yQ>rY-9Ca_uF;Ue$kKlc0+8w?n^Hyiq`W}F-uEIKJhXL3xi(4-jN z&3XZRY@0pZma{`t=}b0AVcEI0MEw4 a$IO%YQvz8Sff^=fq)eUc7i3I5cK`qvb!^T6 delta 320 zcmZp9z}RwuQJR5)fzhcn#gKs^0m$S4Vh}CB!@v+RQQCyDZ)3o2en!Q~34$7%%Y>%# zZftO3TFk8=z$iIcAVGDrp}}8XM#D*F_LGBbr8jFi6f;gf7(O9!Aj z0Y}Ekvpn55vnEVuW)z>C;3zkFkE1>#8%WFKn}PC->_9iYo1B@FI9V*@DptMf5dVO@ w#0?}|q22~Q9Y2!T4z`n+gbg7j5K00Rk|r(Uk%W*U9&PGco=xJ!*kRUI zc$k+!6{)B~bU%>V1oeZq;vrGWS5>K1`-dnJlu970AE=SC3p$sP~7@Jwqj(#ueZ59b8AM-}#O*p$rZ zqY*tv2IC1$kHixRZ7ds!M+S4LRHQSNNsLCi#-q{$+3wkr)xxKJBmCFz~^GH#~n-Rv7&zF znJZ$aa)o~SA__;iyLQ)P&qU9SVAn1Cdk;CJY(jUOp2Atmqa53s1Y}bM5YemTTzXcQ$jyO z;RyFg;#?Jz2PO{Oc7|^{!zWCCI;+2m{^6{LC*m=lC~!z>Zg5dmQbwU*-mPVaGgwbN z+Z^R_91D{9p8L!QGAO(dq%eQzx(Op1T!&nX1i0^LX}~5dVkwUXg&`iBFIwi~I%vW) zmM(5mOz=Zof*7TAUa1XK z*=9M5)%N5ePv<%-wO{Hw$~!qYZ(GTKP&^&e3#Vgx&FQRzvvQ4qunDfptE~u&Nz_m8 z08s2p6thuwmT7^OnHARC>tq%dVGTl5IA~vlmccjnP}K^`P;IYHG~Bham2+~ zWPm|CgO5S1T+#B1<|iFY{4RqA3I%I|y*l*uNRo|=xe3yhZ=p6gQ%TTrDDwwUBQ*N; z4~@MFdX}hu<5D19OuMwj7cPhQnV{&4Eg&%0I~i}6G1UkuNX09bu>K)QcnG^@`i3^RaxI_>ZwEWqY+l7(t?aC(zu#6_yW528!s6~0;d&Edbc;x_ zM@6KWx>R|>u5_B+Y-meE4I^2@k@XCYQ8>pD_7ED62yrrsfd~Ex^|?HvZBF2%0W`}~ za<&0_!`o#;o9U=dxExM)9%nY=4A`SuuytnAS&~VmXv~JY2_`BnQLwDpox!=3ww9ct l0`^Yp?XV-Vc)>$SK%3Dc`zJhFcq)7P@YLbQ9HR}}{{b!z3tRvI delta 1999 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 AFaQ7m delta 571 zcmZ3QGBJ_wG%qg~0}#C4$(r@fbRyp*MzxI#-?Q0tFr+c2^tEtAnWUO#<$zS60vq5(*H|Py}|2DbO+E0th2yK_0m{xl^rJ^0JQeHR-?wg$D|cmme%YS~KrYCTVnrbFftit!@jDj-qv}Nll`m|`ER4c4*se?HUX;-N L$^haOfs6nE_#>4@ diff --git a/fusion_inventory/__manifest__.py b/fusion_inventory/__manifest__.py index 94ea61f1..b6764a12 100644 --- a/fusion_inventory/__manifest__.py +++ b/fusion_inventory/__manifest__.py @@ -4,7 +4,7 @@ { 'name': 'Fusion Inventory', - 'version': '19.0.1.0.0', + 'version': '19.0.1.1.0', 'category': 'Inventory', 'summary': 'Advanced inventory management with margin tracking, sync, portal sheet, and inter-company transfers', 'description': """ diff --git a/fusion_inventory/models/sync_config.py b/fusion_inventory/models/sync_config.py index 6d737c78..c01d8efa 100644 --- a/fusion_inventory/models/sync_config.py +++ b/fusion_inventory/models/sync_config.py @@ -72,15 +72,24 @@ class FusionSyncConfig(models.Model): # ── XML-RPC Connection ── - def _get_xmlrpc_connection(self): + def _get_xmlrpc_connection(self, force=False): self.ensure_one() url = self.url.rstrip('/') try: + models_proxy = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object', allow_none=True) + # Reuse the cached uid to skip the authenticate() handshake — each + # authenticate writes a login-audit row on the remote. execute_kw + # still re-checks the API key on every call, so this stays secure. + # force=True forces a fresh authenticate (Test Connection / manual + # inter-company ops, which must work even if the cache went stale). + if self.remote_uid and not force: + return self.remote_uid, models_proxy common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common', allow_none=True) uid = common.authenticate(self.db_name, self.username, self.api_key, {}) if not uid: raise UserError('Authentication failed. Check username/API key.') - models_proxy = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object', allow_none=True) + if uid != self.remote_uid: + self.sudo().write({'remote_uid': uid}) return uid, models_proxy except xmlrpc.client.Fault as e: raise UserError(f'XML-RPC error: {e.faultString}') @@ -92,7 +101,7 @@ class FusionSyncConfig(models.Model): def action_test_connection(self): self.ensure_one() try: - uid, models_proxy = self._get_xmlrpc_connection() + uid, models_proxy = self._get_xmlrpc_connection(force=True) version_info = xmlrpc.client.ServerProxy( f'{self.url.rstrip("/")}/xmlrpc/2/common', allow_none=True ).version() @@ -174,6 +183,9 @@ class FusionSyncConfig(models.Model): 'state': 'error', 'last_sync': fields.Datetime.now(), 'last_sync_status': error_msg, + # Drop the cached uid so the next run re-authenticates fresh + # (the failure may have been a stale/invalid cached uid). + 'remote_uid': False, }) self.env['fusion.sync.log'].create({ 'config_id': self.id, @@ -544,7 +556,7 @@ class FusionSyncConfig(models.Model): def _create_remote_sale_order(self, product_mapping, qty, partner_name): """Create a sale order on the remote instance for inter-company transfers.""" self.ensure_one() - uid, models_proxy = self._get_xmlrpc_connection() + uid, models_proxy = self._get_xmlrpc_connection(force=True) partners = models_proxy.execute_kw( self.db_name, uid, self.api_key, @@ -593,7 +605,7 @@ class FusionSyncConfig(models.Model): def _create_remote_invoice(self, remote_so_id): """Create and post an invoice for a remote sale order.""" self.ensure_one() - uid, models_proxy = self._get_xmlrpc_connection() + uid, models_proxy = self._get_xmlrpc_connection(force=True) models_proxy.execute_kw( self.db_name, uid, self.api_key, diff --git a/fusion_login_audit/__manifest__.py b/fusion_login_audit/__manifest__.py index 01c2ae6d..9f74ff0d 100644 --- a/fusion_login_audit/__manifest__.py +++ b/fusion_login_audit/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 (Odoo Proprietary License v1.0) { 'name': 'Fusion Login Audit', - 'version': '19.0.1.0.0', + 'version': '19.0.1.1.0', 'category': 'Tools', 'summary': 'Durable login audit log with geo-enrichment, retention, and failure alerts.', 'description': """ diff --git a/fusion_login_audit/models/fusion_login_audit.py b/fusion_login_audit/models/fusion_login_audit.py index 3cc5ebc2..c2a67e5a 100644 --- a/fusion_login_audit/models/fusion_login_audit.py +++ b/fusion_login_audit/models/fusion_login_audit.py @@ -72,6 +72,17 @@ class FusionLoginAudit(models.Model): string='Device Type', default='unknown', ) database = fields.Char(string='Database', size=64) + login_kind = fields.Selection( + [ + ('interactive', 'Interactive'), + ('service', 'Service / Automation'), + ], + string='Login Kind', default='interactive', index=True, + help="Interactive = a real browser/HTTP login. Service = server-to-server " + "auth (XML-RPC/JSON-RPC, cron, inter-instance sync) with no HTTP " + "request. Service logins are hidden from the default Login Events " + "view to keep it focused on real user activity.", + ) # Odoo 19 replaces the legacy `_sql_constraints = [...]` list with # declarative `models.Constraint` attributes. The plan template used the diff --git a/fusion_login_audit/models/res_users.py b/fusion_login_audit/models/res_users.py index c776b244..818fffb2 100644 --- a/fusion_login_audit/models/res_users.py +++ b/fusion_login_audit/models/res_users.py @@ -86,11 +86,16 @@ class ResUsers(models.Model): else: vals['device_type'] = 'unknown' vals['geo_lookup_state'] = 'pending' + # A live HTTP request means a real browser/interactive login. + vals['login_kind'] = 'interactive' else: vals['ip_address'] = 'internal' vals['user_agent_raw'] = '' vals['device_type'] = 'unknown' vals['geo_lookup_state'] = 'internal' + # No HTTP request = server-to-server auth (XML-RPC/JSON-RPC, cron, + # inter-instance sync). Tagged so the default view can hide it. + vals['login_kind'] = 'service' # _credential is accepted in the signature so callers (T6 _check_credentials, # T7 _login) can hand the dict in without filtering. The helper deliberately @@ -388,5 +393,6 @@ class ResUsers(models.Model): 'view_mode': 'list,form', 'domain': [('user_id', '=', self.id)], 'context': {'create': False, 'edit': False, 'delete': False, - 'default_user_id': self.id}, + 'default_user_id': self.id, + 'search_default_filter_interactive': 1}, } diff --git a/fusion_login_audit/tests/test_login_audit.py b/fusion_login_audit/tests/test_login_audit.py index e6926e64..4cf74c8f 100644 --- a/fusion_login_audit/tests/test_login_audit.py +++ b/fusion_login_audit/tests/test_login_audit.py @@ -74,6 +74,7 @@ class TestFusionLoginAuditModel(TransactionCase): self.assertEqual(vals['ip_address'], 'internal') self.assertEqual(vals['user_agent_raw'], '') self.assertEqual(vals['geo_lookup_state'], 'internal') + self.assertEqual(vals['login_kind'], 'service') self.assertEqual(vals['database'], self.env.cr.dbname) def test_build_event_vals_parses_user_agent(self): @@ -91,6 +92,7 @@ class TestFusionLoginAuditModel(TransactionCase): self.assertIn('Windows', vals['os']) self.assertEqual(vals['device_type'], 'desktop') self.assertEqual(vals['geo_lookup_state'], 'pending') + self.assertEqual(vals['login_kind'], 'interactive') def test_build_event_vals_strips_password(self): """If a credential dict sneaks in, no password leaks into vals.""" diff --git a/fusion_login_audit/views/fusion_login_audit_views.xml b/fusion_login_audit/views/fusion_login_audit_views.xml index 526e5b1a..df81aec8 100644 --- a/fusion_login_audit/views/fusion_login_audit_views.xml +++ b/fusion_login_audit/views/fusion_login_audit_views.xml @@ -14,6 +14,7 @@ + @@ -36,6 +37,7 @@ + @@ -77,6 +79,11 @@ + + + + @@ -104,7 +113,10 @@ fusion.login.audit list,form - {} + + {'search_default_filter_interactive': 1} diff --git a/fusion_plating/fusion_plating_configurator/__manifest__.py b/fusion_plating/fusion_plating_configurator/__manifest__.py index eafac894..8b0bd91b 100644 --- a/fusion_plating/fusion_plating_configurator/__manifest__.py +++ b/fusion_plating/fusion_plating_configurator/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Fusion Plating — Configurator', - 'version': '19.0.23.6.0', + 'version': '19.0.22.10.0', 'category': 'Manufacturing/Plating', 'summary': 'Quotation configurator with part catalog, coating configs, and formula-based pricing engine.', 'description': """ @@ -44,7 +44,6 @@ Provides: 'views/fp_part_catalog_views.xml', 'views/fp_process_node_part_scoped_views.xml', 'views/fp_pricing_rule_views.xml', - 'views/fp_additional_charge_type_views.xml', 'views/fp_quote_configurator_views.xml', 'views/sale_order_views.xml', 'views/res_partner_views.xml', @@ -60,7 +59,6 @@ Provides: 'views/fp_configurator_menu.xml', 'views/fp_so_job_sort_views.xml', 'data/fp_sale_description_template_data.xml', - 'data/fp_additional_charge_type_data.xml', ], 'assets': { 'web.assets_backend': [ diff --git a/fusion_plating/fusion_plating_configurator/views/fp_express_order_views.xml b/fusion_plating/fusion_plating_configurator/views/fp_express_order_views.xml index f2f9a2bd..5d4e7578 100644 --- a/fusion_plating/fusion_plating_configurator/views/fp_express_order_views.xml +++ b/fusion_plating/fusion_plating_configurator/views/fp_express_order_views.xml @@ -233,10 +233,6 @@ OPEN open the part record -
- - Lot Order — price each line as a flat lot total (qty preserved for production) -