Split 49 modules/suites into independent git repos; untrack from monorepo
Each top-level module/suite folder is now its own private repo on GitHub (gsinghpal/<name>) and gitea (admin/<name>), with a fresh single initial commit. The monorepo no longer tracks them (added to .gitignore + git rm --cached); working-tree files are retained on disk and managed in their own repos. The monorepo keeps shared root files (CLAUDE.md, docs/, scripts/, tools/, AGENTS.md, WIP/obsolete dirs) and full history. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,189 +0,0 @@
|
||||
"""Sub 4 smoke test — runs inside odoo-shell on entech.
|
||||
|
||||
Verifies: toggle-triggered banner, lazy review creation, roster-enforced
|
||||
sign flow, compute-driven auto-dismiss on confirmed MO, re-open flow,
|
||||
risk-band matrix.
|
||||
"""
|
||||
env = env # odoo-shell injects this
|
||||
|
||||
Partner = env['res.partner']
|
||||
Part = env['fp.part.catalog']
|
||||
Review = env['fp.contract.review']
|
||||
Users = env['res.users']
|
||||
Company = env.company
|
||||
|
||||
# ---- Roster: add admin to both rosters ---------------------------------
|
||||
admin = env.ref('base.user_admin')
|
||||
Company.write({
|
||||
'x_fc_qa_assistant_user_ids': [(6, 0, [admin.id])],
|
||||
'x_fc_qa_manager_user_ids': [(6, 0, [admin.id])],
|
||||
})
|
||||
assert admin in Company.x_fc_qa_assistant_user_ids
|
||||
assert admin in Company.x_fc_qa_manager_user_ids
|
||||
print('[OK] Company rosters populated')
|
||||
|
||||
# ---- Customer with contract_review_required ----------------------------
|
||||
cust = Partner.create({
|
||||
'name': 'Sub4 Smoke Customer',
|
||||
'is_company': True,
|
||||
'customer_rank': 1,
|
||||
'x_fc_contract_review_required': True,
|
||||
})
|
||||
assert cust.x_fc_contract_review_required
|
||||
print('[OK] Customer toggle set')
|
||||
|
||||
# ---- Part under that customer → banner visible -------------------------
|
||||
part = Part.create({
|
||||
'partner_id': cust.id,
|
||||
'part_number': 'SUB4-SMOKE-001',
|
||||
'revision': 'A',
|
||||
})
|
||||
part.invalidate_recordset()
|
||||
assert part.x_fc_customer_requires_contract_review
|
||||
# v19.0.4.10.0 — create() now auto-stages the review when the customer
|
||||
# has enforcement enabled, so the review record exists immediately and
|
||||
# the banner correspondingly hides (banner = "no review yet"). The
|
||||
# action_start_contract_review path remains valid for parts created
|
||||
# before enforcement was enabled or via flows that bypass create().
|
||||
assert part.x_fc_contract_review_id, 'review should be auto-created on create()'
|
||||
print('[OK] Review auto-created on part create')
|
||||
|
||||
# ---- Start contract review → opens the existing record ---------------
|
||||
action = part.action_start_contract_review()
|
||||
part.invalidate_recordset()
|
||||
review = part.x_fc_contract_review_id
|
||||
assert review, 'review should exist'
|
||||
assert review.state == 'assistant_review'
|
||||
assert review.customer_id == cust
|
||||
assert review.part_number == 'SUB4-SMOKE-001'
|
||||
print('[OK] action_start_contract_review opens the auto-created review')
|
||||
|
||||
# ---- Sign section 2.0 as admin (roster ok) -----------------------------
|
||||
review.with_user(admin).action_sign_section_20()
|
||||
review.invalidate_recordset()
|
||||
assert review.s20_locked
|
||||
assert review.s20_signed_by == admin
|
||||
assert review.state == 'manager_review'
|
||||
print('[OK] Section 2.0 signed; state advanced')
|
||||
|
||||
# ---- Sign section 3.0 → state = complete -------------------------------
|
||||
review.s30_risk_consequence = '4'
|
||||
review.s30_risk_likelihood = '4'
|
||||
assert review.s30_risk_band == 'red', f'expected red, got {review.s30_risk_band}'
|
||||
review.with_user(admin).action_sign_section_30()
|
||||
review.invalidate_recordset()
|
||||
assert review.s30_locked
|
||||
assert review.state == 'complete'
|
||||
print('[OK] Section 3.0 signed; review complete; risk matrix computed')
|
||||
|
||||
# ---- Banner now hidden (review complete) -------------------------------
|
||||
part.invalidate_recordset()
|
||||
assert not part.x_fc_contract_review_banner_visible
|
||||
print('[OK] Banner hidden after completion')
|
||||
|
||||
# ---- Re-open (admin is manager) ----------------------------------------
|
||||
review.action_reopen()
|
||||
review.invalidate_recordset()
|
||||
assert review.state == 'assistant_review'
|
||||
assert not review.s20_locked
|
||||
assert not review.s30_locked
|
||||
print('[OK] Re-open cleared both sections')
|
||||
|
||||
# ---- Risk matrix parity with paper form --------------------------------
|
||||
expected = {
|
||||
(1, 1): 'green', (1, 2): 'green', (1, 3): 'green', (1, 4): 'green', (1, 5): 'green',
|
||||
(2, 1): 'green', (2, 2): 'green', (2, 3): 'yellow', (2, 4): 'yellow', (2, 5): 'yellow',
|
||||
(3, 1): 'green', (3, 2): 'yellow', (3, 3): 'yellow', (3, 4): 'yellow', (3, 5): 'red',
|
||||
(4, 1): 'yellow', (4, 2): 'yellow', (4, 3): 'yellow', (4, 4): 'red', (4, 5): 'red',
|
||||
(5, 1): 'yellow', (5, 2): 'yellow', (5, 3): 'red', (5, 4): 'red', (5, 5): 'red',
|
||||
}
|
||||
for (c, l), band in expected.items():
|
||||
review.s30_risk_consequence = str(c)
|
||||
review.s30_risk_likelihood = str(l)
|
||||
assert review.s30_risk_band == band, (
|
||||
f'matrix mismatch at c={c} l={l}: got {review.s30_risk_band} expected {band}'
|
||||
)
|
||||
print('[OK] 25-cell risk matrix matches paper form')
|
||||
|
||||
# ---- Dismiss flow ------------------------------------------------------
|
||||
part2 = Part.create({
|
||||
'partner_id': cust.id,
|
||||
'part_number': 'SUB4-SMOKE-002',
|
||||
'revision': 'A',
|
||||
})
|
||||
part2.invalidate_recordset()
|
||||
assert part2.x_fc_contract_review_banner_visible
|
||||
part2.action_dismiss_contract_review()
|
||||
part2.invalidate_recordset()
|
||||
assert part2.x_fc_contract_review_dismissed
|
||||
assert not part2.x_fc_contract_review_banner_visible
|
||||
print('[OK] Dismiss hides banner')
|
||||
|
||||
# ---- Non-roster user blocked ------------------------------------------
|
||||
demo_user = Users.search([('login', '=', 'demo')], limit=1)
|
||||
if demo_user:
|
||||
part3 = Part.create({
|
||||
'partner_id': cust.id,
|
||||
'part_number': 'SUB4-SMOKE-003',
|
||||
'revision': 'A',
|
||||
})
|
||||
part3.action_start_contract_review()
|
||||
part3.invalidate_recordset()
|
||||
rev3 = part3.x_fc_contract_review_id
|
||||
try:
|
||||
rev3.with_user(demo_user).action_sign_section_20()
|
||||
assert False, 'non-roster user should have been blocked'
|
||||
except Exception as e:
|
||||
assert 'authorised' in str(e) or 'Plating Manager' in str(e)
|
||||
print('[OK] Non-roster user blocked')
|
||||
else:
|
||||
print('[SKIP] No demo user for non-roster check')
|
||||
|
||||
# ---- Bulk-toggle (Check All / Clear All) buttons ----------------------
|
||||
part4 = Part.create({
|
||||
'partner_id': cust.id,
|
||||
'part_number': 'SUB4-SMOKE-004',
|
||||
'revision': 'A',
|
||||
})
|
||||
part4.action_start_contract_review()
|
||||
part4.invalidate_recordset()
|
||||
rev4 = part4.x_fc_contract_review_id
|
||||
|
||||
rev4.action_check_all_section_20()
|
||||
for f in rev4._SECTION_20_CHECKLIST:
|
||||
assert rev4[f] is True, f'{f} should be True after Check All'
|
||||
print('[OK] Section 2.0 Check All ticks all 10 boxes')
|
||||
|
||||
rev4.action_clear_all_section_20()
|
||||
for f in rev4._SECTION_20_CHECKLIST:
|
||||
assert rev4[f] is False, f'{f} should be False after Clear All'
|
||||
print('[OK] Section 2.0 Clear All clears all 10 boxes')
|
||||
|
||||
rev4.action_check_all_section_30()
|
||||
for f in rev4._SECTION_30_CHECKLIST:
|
||||
assert rev4[f] is True, f'{f} should be True after Check All'
|
||||
print('[OK] Section 3.0 Check All ticks all 11 boxes')
|
||||
|
||||
rev4.action_clear_all_section_30()
|
||||
for f in rev4._SECTION_30_CHECKLIST:
|
||||
assert rev4[f] is False, f'{f} should be False after Clear All'
|
||||
print('[OK] Section 3.0 Clear All clears all 11 boxes')
|
||||
|
||||
# Lock section 2.0, bulk toggle should refuse
|
||||
rev4.with_user(admin).action_sign_section_20()
|
||||
try:
|
||||
rev4.action_check_all_section_20()
|
||||
assert False, 'bulk toggle should fail on locked section'
|
||||
except Exception as e:
|
||||
assert 'locked' in str(e).lower() or 'signed' in str(e).lower()
|
||||
print('[OK] Bulk toggle blocked on locked section')
|
||||
|
||||
# ---- QWeb render -------------------------------------------------------
|
||||
report = env.ref('fusion_plating_quality.action_report_contract_review')
|
||||
pdf_bytes, mime = report._render_qweb_pdf('fusion_plating_quality.report_contract_review_qa005', [review.id])
|
||||
assert pdf_bytes and pdf_bytes[:4] == b'%PDF'
|
||||
print(f'[OK] QA-005 PDF rendered ({len(pdf_bytes)} bytes)')
|
||||
|
||||
# ---- Cleanup -----------------------------------------------------------
|
||||
env.cr.rollback()
|
||||
print('\n=== SUB 4 SMOKE PASS — all assertions held ===')
|
||||
Reference in New Issue
Block a user