"""A proposed business-case state model, not a queue or accounting integration."""
from dataclasses import dataclass,field
import json,hashlib
@dataclass
class Case:
 supplier:str='SUP1'
 invoice:str='I17'
 state:str='new'
 owner:str|None=None
 reason:str|None=None
 current:str|None=None
 documents:dict=field(default_factory=dict)
 messages:dict=field(default_factory=dict)
 resolutions:list=field(default_factory=list)
 history:list=field(default_factory=list)
 def receive(self,message,document,content):
  if message in self.messages:return 'duplicate_delivery'
  digest=hashlib.sha256(content.encode()).hexdigest()
  for existing,info in self.documents.items():
   if info['digest']==digest:
    self.messages[message]=existing
    return 'duplicate_document'
  self.messages[message]=document
  self.documents[document]={'digest':digest}
  if self.current is None:self.current=document
  else:self.state='revision_review';self.reason='new_document_requires_review'
  self.history.append({'event':message,'document':document,'state':self.state});return 'document_added'
 def assign(self,actor):
  if self.owner is not None and self.owner!=actor:raise ValueError('already_assigned')
  self.owner=actor
  if self.state=='new':self.state='assigned'
 def select(self,actor,document):
  if actor!=self.owner or document not in self.documents:raise ValueError('not_permitted')
  self.current=document;self.state='assigned';self.reason=None
 def check(self,actor,purchase_order_matches):
  if actor!=self.owner:raise ValueError('not_owner')
  if self.state not in {'assigned','waiting'}:raise ValueError('review_or_select_document_first')
  self.state='ready' if purchase_order_matches else 'waiting'
  self.reason=None if purchase_order_matches else 'purchase_order_mismatch'
 def resolve(self,actor,document,export_ref):
  if actor!=self.owner or self.state!='ready' or document!=self.current or not export_ref:raise ValueError('resolution_requirements_not_met')
  self.resolutions.append({'document':document,'export_ref':export_ref});self.state='resolved';self.reason=None
c=Case();checks=[]
assert c.receive('E1','D1','Synthetic invoice I17, missing purchase order, total12000p')=='document_added';c.assign('OP1');c.check('OP1',False)
checks.append({'step':'D1 awaiting order match','state':c.state,'current':c.current,'reason':c.reason})
assert c.receive('E1','D1','Synthetic invoice I17, missing purchase order, total12000p')=='duplicate_delivery'
assert len(c.messages)==1 and len(c.documents)==1
assert c.receive('E2','D1-copy','Synthetic invoice I17, missing purchase order, total12000p')=='duplicate_document'
assert len(c.messages)==2 and len(c.documents)==1
checks.append({'step':'same event then same bytes under new event','state':c.state,'documents':len(c.documents),'messages':len(c.messages)})
try:c.assign('OP2');raise AssertionError('double owner accepted')
except ValueError:pass
assert c.receive('E3','D2','Synthetic corrected invoice I17, PO23, total11000p')=='document_added'
assert c.state=='revision_review' and c.current=='D1'
try:c.check('OP1',True);raise AssertionError('unreviewed correction skipped')
except ValueError:pass
checks.append({'step':'correction arrives, not yet selected','state':c.state,'current':c.current,'documents':len(c.documents)})
c.select('OP1','D2');c.check('OP1',False)
try:c.resolve('OP1','D2','EXPORT17');raise AssertionError('waiting case closed')
except ValueError:pass
checks.append({'step':'selected D2 with wrong purchase order','state':c.state,'current':c.current,'reason':c.reason})
c.receive('E4','D3','Synthetic corrected invoice I17, PO17, total11000p');c.select('OP1','D3');c.check('OP1',True)
for doc,ref in [('D2','EXPORT17'),('D3','')]:
 try:c.resolve('OP1',doc,ref);raise AssertionError('invalid resolution accepted')
 except ValueError:pass
c.resolve('OP1','D3','EXPORT17');assert c.state=='resolved'
checks.append({'step':'D3 matched and export confirmed','state':c.state,'current':c.current,'resolution':c.resolutions[-1]})
c.receive('E5','D4','Synthetic later correction I17, PO17, total10000p')
assert c.state=='revision_review' and c.current=='D3' and c.resolutions==[{'document':'D3','export_ref':'EXPORT17'}]
checks.append({'step':'later correction after resolution','state':c.state,'current':c.current,'prior_resolution_retained':True})
report={'allAssertionsPassed':True,'case_key':[c.supplier,c.invoice],'final_documents':len(c.documents),'final_messages':len(c.messages),'owner':c.owner,'checks':checks,'limits':['Constructed in-memory proposed state machine, not concurrent assignment persistence.','Document grouping/correction selection requires a verified supplier/invoice association; this code does not extract it.','EXPORT17 is a synthetic supplied confirmation; no accounting API called.','No financial policy or real invoice data tested.']}
if __name__=='__main__':print(json.dumps(report,indent=2))
