100 lines
3.5 KiB
Python
100 lines
3.5 KiB
Python
# Step 5 — Carlos walks the plating job. Test BOTH paths:
|
|
# A) Try to mark_done with steps still ready → must be blocked
|
|
# B) Walk every step → mark_done succeeds
|
|
|
|
# Build a fresh SO + job (don't reuse 423 — its job is already done).
|
|
from odoo import fields
|
|
W = env['fp.direct.order.wizard']
|
|
Line = env['fp.direct.order.line']
|
|
P = env['res.partner']
|
|
Part = env['fp.part.catalog']
|
|
|
|
target = P.browse(2529)
|
|
part = Part.search([('x_fc_default_coating_config_id', '!=', False)], limit=1)
|
|
|
|
w = W.create({
|
|
'partner_id': target.id, 'po_pending': True,
|
|
'po_number': 'PO-STEP5-001',
|
|
'planned_start_date': fields.Date.today(),
|
|
'customer_deadline': fields.Date.add(fields.Date.today(), days=14),
|
|
'invoice_strategy': 'net_terms',
|
|
'delivery_method': 'shipping_partner',
|
|
})
|
|
w._onchange_partner_id()
|
|
ln = Line.new({'wizard_id': w.id})
|
|
ln.part_catalog_id = part
|
|
ln._onchange_part_clears_variant()
|
|
Line.create({
|
|
'wizard_id': w.id, 'part_catalog_id': part.id,
|
|
'coating_config_id': ln.coating_config_id.id,
|
|
'quantity': 10, 'unit_price': 15.0,
|
|
})
|
|
result = w.action_create_order()
|
|
so = env['sale.order'].browse(result['res_id'])
|
|
so.action_confirm()
|
|
job = env['fp.job'].search([('sale_order_id', '=', so.id)], limit=1)
|
|
print(f'[Carlos] Fresh job {job.name} for SO {so.name}')
|
|
print(f' Steps: {len(job.step_ids)}, all in state: {set(job.step_ids.mapped("state"))}')
|
|
|
|
# Path A: try mark_done without walking steps.
|
|
print()
|
|
print('[Carlos] Try Mark Done WITHOUT walking any step (compliance test):')
|
|
try:
|
|
job.button_mark_done()
|
|
print(' ❌ JOB CLOSED WITH ZERO STEPS WALKED — guard failed')
|
|
except Exception as e:
|
|
print(f' ✓ blocked: {str(e)[:200]}')
|
|
|
|
# Path B: walk every step then mark_done.
|
|
print()
|
|
print('[Carlos] Walk every step, then Mark Done:')
|
|
for s in job.step_ids.sorted('sequence'):
|
|
if s.state in ('pending', 'ready'):
|
|
s.button_start()
|
|
if s.state == 'in_progress':
|
|
s.button_finish()
|
|
done_count = len(job.step_ids.filtered(lambda s: s.state == 'done'))
|
|
print(f' walked {done_count}/{len(job.step_ids)} to done')
|
|
|
|
try:
|
|
job.button_mark_done()
|
|
print(f' ✓ Job marked done — state={job.state}, finished={job.date_finished}')
|
|
except Exception as e:
|
|
print(f' ❌ Mark Done failed AFTER walking: {e}')
|
|
|
|
# Verify side effects on this job too.
|
|
Delivery = env['fusion.plating.delivery']
|
|
deliveries = Delivery.search([('x_fc_job_id', '=', job.id)])
|
|
Cert = env['fp.certificate']
|
|
certs = Cert.search([('x_fc_job_id', '=', job.id)])
|
|
print(f' Side effects: {len(deliveries)} delivery, {len(certs)} certificate')
|
|
|
|
# Path C: manager bypass (admin is a manager).
|
|
print()
|
|
print('[Mgr] Test manager bypass via context fp_skip_step_gate=True')
|
|
w2 = W.create({
|
|
'partner_id': target.id, 'po_pending': True,
|
|
'po_number': 'PO-STEP5-002',
|
|
'invoice_strategy': 'net_terms',
|
|
})
|
|
w2._onchange_partner_id()
|
|
Line.create({
|
|
'wizard_id': w2.id, 'part_catalog_id': part.id,
|
|
'coating_config_id': part.x_fc_default_coating_config_id.id,
|
|
'quantity': 5, 'unit_price': 15.0,
|
|
})
|
|
r2 = w2.action_create_order()
|
|
so2 = env['sale.order'].browse(r2['res_id'])
|
|
so2.action_confirm()
|
|
job2 = env['fp.job'].search([('sale_order_id', '=', so2.id)], limit=1)
|
|
print(f' Created fresh job {job2.name} with {len(job2.step_ids)} unworked steps')
|
|
try:
|
|
job2.with_context(fp_skip_step_gate=True).button_mark_done()
|
|
print(f' ✓ Manager bypass worked — job state={job2.state}')
|
|
except Exception as e:
|
|
print(f' ❌ Bypass failed: {e}')
|
|
|
|
env.cr.commit()
|
|
print()
|
|
print('== Step 5 complete ==')
|