mirror of https://github.com/NaN-tic/nanscan.git
Code cleanup and workflow improvements.
- Removed '_id' postfix in relation fields. - Added relation with templatebox in document boxes. - Improved workflow with background alternative to scan process. - Background scanning process sends a request to the user when it's finished.
This commit is contained in:
parent
67edd150b1
commit
100fc8b3bc
|
@ -607,7 +607,7 @@ class MainWindow(QMainWindow):
|
|||
|
||||
if self._template.id:
|
||||
Rpc.session.call( '/object', 'execute', 'nan.template', 'write', [self._template.id], {'name': self._template.name } )
|
||||
ids = Rpc.session.call( '/object', 'execute', 'nan.template.box', 'search', [('template_id','=',self._template.id)] )
|
||||
ids = Rpc.session.call( '/object', 'execute', 'nan.template.box', 'search', [('template','=',self._template.id)] )
|
||||
Rpc.session.call( '/object', 'execute', 'nan.template.box', 'unlink', ids )
|
||||
else:
|
||||
self._template.id = Rpc.session.call( '/object', 'execute', 'nan.template', 'create', {'name': self._template.name } )
|
||||
|
@ -621,7 +621,7 @@ class MainWindow(QMainWindow):
|
|||
'feature_y' : x.featureRect.y(),
|
||||
'feature_width' : x.featureRect.width(),
|
||||
'feature_height' : x.featureRect.height(),
|
||||
'template_id': self._template.id,
|
||||
'template': self._template.id,
|
||||
'name': x.name,
|
||||
'text': x.text,
|
||||
'recognizer': x.recognizer,
|
||||
|
|
|
@ -34,7 +34,7 @@ class TemplateStorageManager:
|
|||
def save(template):
|
||||
if template.id:
|
||||
Rpc.session.call( '/object', 'execute', 'nan.template', 'write', [template.id], {'name': template.name } )
|
||||
ids = Rpc.session.call( '/object', 'execute', 'nan.template.box', 'search', [('template_id','=',template.id)] )
|
||||
ids = Rpc.session.call( '/object', 'execute', 'nan.template.box', 'search', [('template','=',template.id)] )
|
||||
Rpc.session.call( '/object', 'execute', 'nan.template.box', 'unlink', ids )
|
||||
else:
|
||||
template.id = Rpc.session.call( '/object', 'execute', 'nan.template', 'create', {'name': template.name } )
|
||||
|
@ -48,7 +48,7 @@ class TemplateStorageManager:
|
|||
'feature_y' : x.featureRect.y(),
|
||||
'feature_width' : x.featureRect.width(),
|
||||
'feature_height' : x.featureRect.height(),
|
||||
'template_id': template.id,
|
||||
'template': template.id,
|
||||
'name': x.name,
|
||||
'text': x.text,
|
||||
'recognizer': x.recognizer,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
export PYTHONPATH=../../ktiny/bin
|
||||
export PYTHONPATH=/home/albert/d/koo
|
||||
./loader.py $1 $2
|
||||
|
||||
|
|
|
@ -35,7 +35,8 @@
|
|||
"category" : "Generic Modules/Attachments",
|
||||
"init_xml" : [],
|
||||
"demo_xml" : [],
|
||||
"update_xml" : ["auto_attach_view.xml", "auto_attach_wizard.xml", "auto_attach_workflow.xml"],
|
||||
"update_xml" : ["auto_attach_view.xml", "auto_attach_wizard.xml",
|
||||
"auto_attach_workflow.xml", "auto_attach_data.xml"],
|
||||
"active": False,
|
||||
"installable": True
|
||||
}
|
||||
|
|
|
@ -46,10 +46,10 @@ class nan_template(osv.osv):
|
|||
_name = 'nan.template'
|
||||
_columns = {
|
||||
'name' : fields.char('Name', 64, required=True),
|
||||
'boxes' : fields.one2many('nan.template.box', 'template_id', 'Boxes'),
|
||||
'boxes' : fields.one2many('nan.template.box', 'template', 'Boxes'),
|
||||
'attach_function' : fields.char('Attachment Function', 256),
|
||||
'action_function' : fields.char('Action Function', 256),
|
||||
'documents' : fields.one2many('nan.document', 'template_id', 'Documents')
|
||||
'documents' : fields.one2many('nan.document', 'template', 'Documents')
|
||||
}
|
||||
|
||||
# Returns a Template from the fields of a template. You'll usually use
|
||||
|
@ -57,10 +57,11 @@ class nan_template(osv.osv):
|
|||
def getTemplateFromData(self, cr, uid, data):
|
||||
template = Template( data['name'] )
|
||||
template.id = data['id']
|
||||
ids = self.pool.get('nan.template.box').search( cr, uid, [('template_id','=',data['id'])] )
|
||||
ids = self.pool.get('nan.template.box').search( cr, uid, [('template','=',data['id'])] )
|
||||
boxes = self.pool.get('nan.template.box').read(cr, uid, ids)
|
||||
for y in boxes:
|
||||
box = TemplateBox()
|
||||
box.id = y['id']
|
||||
box.rect = QRectF( y['x'], y['y'], y['width'], y['height'] )
|
||||
box.name = y['name']
|
||||
box.text = y['text']
|
||||
|
@ -97,7 +98,7 @@ nan_template()
|
|||
class nan_template_box(osv.osv):
|
||||
_name = 'nan.template.box'
|
||||
_columns = {
|
||||
'template_id' : fields.many2one('nan.template', 'Template', required=True, ondelete='cascade'),
|
||||
'template' : fields.many2one('nan.template', 'Template', required=True, ondelete='cascade'),
|
||||
'x' : fields.float('X'),
|
||||
'y' : fields.float('Y'),
|
||||
'width' : fields.float('Width'),
|
||||
|
@ -125,12 +126,13 @@ class nan_document(osv.osv):
|
|||
_columns = {
|
||||
'name' : fields.char('Name', 64),
|
||||
'datas': fields.binary('Data'),
|
||||
'properties': fields.one2many('nan.document.property', 'document_id', 'Properties'),
|
||||
'template_id': fields.many2one('nan.template', 'Template' ),
|
||||
'properties': fields.one2many('nan.document.property', 'document', 'Properties'),
|
||||
'template': fields.many2one('nan.template', 'Template' ),
|
||||
'document': fields.reference('Document', selection=attachableDocuments, size=128),
|
||||
'task' : fields.text('Task', readonly=True),
|
||||
'state': fields.selection( [('pending','Pending'),('scanned','Scanned'),
|
||||
('verified','Verified'),('processed','Processed')],
|
||||
'state': fields.selection( [('pending','Pending'),('scanning','Scanning'),
|
||||
('scanned','Scanned'), ('verified','Verified'),('processing','Processing'),
|
||||
('processed','Processed')],
|
||||
'State', required=True, readonly=True )
|
||||
}
|
||||
_defaults = {
|
||||
|
@ -142,20 +144,31 @@ class nan_document(osv.osv):
|
|||
# the meanwhile" would be thrown, so by now check which of the records
|
||||
# we'll want to scan later
|
||||
toScan = []
|
||||
if 'template_id' in values:
|
||||
for x in self.read( cr, uid, ids, ['state', 'template_id'], context ):
|
||||
# We only scan the document if template_id has changed and the document
|
||||
if 'template' in values:
|
||||
for x in self.read( cr, uid, ids, ['state', 'template'], context ):
|
||||
# We only scan the document if template has changed and the document
|
||||
# is in 'scanned' state.
|
||||
if x['state'] == 'scanned' and x['template_id'] != values['template_id']:
|
||||
toScan.append( {'id': x['id'], 'template_id': values['template_id'] } )
|
||||
if x['state'] == 'scanned' and x['template'] != values['template']:
|
||||
toScan.append( {'id': x['id'], 'template': values['template'] } )
|
||||
|
||||
ret = super(nan_document, self).write(cr, uid, ids, values, context)
|
||||
|
||||
for x in toScan:
|
||||
self.scanDocumentWithTemplate( cr, uid, x['id'], x['template_id'] )
|
||||
self.scanDocumentWithTemplate( cr, uid, x['id'], x['template'] )
|
||||
return ret
|
||||
|
||||
def scan_document(self, cr, uid, imageIds):
|
||||
def scan_document_background(self, cr, uid, imageIds):
|
||||
self.pool.get('ir.cron').create(cr, uid, {
|
||||
'name': 'Scan document',
|
||||
'user_id': uid,
|
||||
'model': 'nan.document',
|
||||
'function': 'scan_document',
|
||||
'args': repr([ imageIds, True ])
|
||||
})
|
||||
cr.commit()
|
||||
|
||||
# If notify=True sends a request/notification to uid
|
||||
def scan_document(self, cr, uid, imageIds, notify=False):
|
||||
# Load templates into 'templates' list
|
||||
templates = self.pool.get('nan.template').getAllTemplates( cr, uid )
|
||||
|
||||
|
@ -165,15 +178,14 @@ class nan_document(osv.osv):
|
|||
|
||||
# Iterate over all images and try to find the most similar template
|
||||
for document in self.browse(cr, uid, imageIds):
|
||||
#TODO: Enable workflow test
|
||||
#if document.state != 'pending':
|
||||
# continue
|
||||
if document.state not in ('pending','scanning'):
|
||||
continue
|
||||
fp, image = tempfile.mkstemp()
|
||||
fp = os.fdopen( fp, 'wb+' )
|
||||
fp.write( base64.decodestring(document.datas) )
|
||||
fp.close()
|
||||
recognizer.recognize( image )
|
||||
result = recognizer.findMatchingTemplate( templates )
|
||||
recognizer.recognize( QImage( image ) )
|
||||
result = recognizer.findMatchingTemplateByOffset( templates )
|
||||
template = result['template']
|
||||
doc = result['document']
|
||||
if not template:
|
||||
|
@ -185,14 +197,29 @@ class nan_document(osv.osv):
|
|||
template_id = template.id
|
||||
else:
|
||||
template_id = False
|
||||
self.write(cr, uid, [document.id], {'template_id': template_id, 'state': 'scanned'})
|
||||
self.write(cr, uid, [document.id], {'template': template_id, 'state': 'scanned'})
|
||||
if doc:
|
||||
obj = self.pool.get('nan.document.property')
|
||||
for box in doc.boxes:
|
||||
obj.create(cr, uid, { 'name' : box.templateBox.name, 'value' : box.text, 'document_id': document.id } )
|
||||
obj.create(cr, uid, {
|
||||
'name': box.templateBox.name,
|
||||
'value': box.text,
|
||||
'document': document.id,
|
||||
'template_box': box.templateBox.id
|
||||
})
|
||||
|
||||
if notify:
|
||||
self.pool.get('res.request').create( cr, uid, {
|
||||
'act_from': uid,
|
||||
'act_to': uid,
|
||||
'name': 'Finished scanning document',
|
||||
'body': 'The auto_attach system has finished scanning the document you requested. A reference to the document can be found in field Document Ref 1.',
|
||||
'ref_doc1': 'nan.document,%d' % document.id,
|
||||
})
|
||||
|
||||
self.executeAttachs( cr, uid, imageIds )
|
||||
self.executeActions( cr, uid, imageIds, True )
|
||||
|
||||
cr.commit()
|
||||
|
||||
def scanDocumentWithTemplate(self, cr, uid, documentId, templateId):
|
||||
|
@ -200,7 +227,7 @@ class nan_document(osv.osv):
|
|||
# Whether templateId is valid or not
|
||||
# Remove previous properties
|
||||
obj = self.pool.get('nan.document.property')
|
||||
ids = obj.search( cr, uid, [('document_id','=',documentId)] )
|
||||
ids = obj.search( cr, uid, [('document','=',documentId)] )
|
||||
obj.unlink( cr, uid, ids )
|
||||
|
||||
if templateId:
|
||||
|
@ -224,7 +251,12 @@ class nan_document(osv.osv):
|
|||
doc = recognizer.extractWithTemplate( image, template )
|
||||
|
||||
for box in doc.boxes:
|
||||
obj.create(cr, uid, { 'name' : box.templateBox.name, 'value' : box.text, 'document_id': document['id'] } )
|
||||
obj.create(cr, uid, {
|
||||
'name': box.templateBox.name,
|
||||
'value': box.text,
|
||||
'document': document['id'],
|
||||
'template_box': box.templateBox.id
|
||||
})
|
||||
self.executeAttachs( cr, uid, [documentId] )
|
||||
self.executeActions( cr, uid, [documentId], True )
|
||||
cr.commit()
|
||||
|
@ -259,13 +291,14 @@ class nan_document(osv.osv):
|
|||
|
||||
def executeActions( self, cr, uid, ids, explain ):
|
||||
for document in self.browse( cr, uid, ids ):
|
||||
#TODO: Enable workflow test
|
||||
#if not explain and document.state != 'verified':
|
||||
#continue
|
||||
print "Executing action on document with state ", document.state
|
||||
if not explain and document.state not in ('verified','processing'):
|
||||
continue
|
||||
|
||||
print "Yes"
|
||||
task = None
|
||||
if document.template_id:
|
||||
function = document.template_id.action_function
|
||||
if document.template:
|
||||
function = document.template.action_function
|
||||
if function:
|
||||
properties = dict( [(x.name, unicode(x.value)) for x in document.properties] )
|
||||
(name, parameters) = self._parseFunction(function, properties)
|
||||
|
@ -279,23 +312,22 @@ class nan_document(osv.osv):
|
|||
ref = document.document.split(',')
|
||||
model = ref[0]
|
||||
id = ref[1]
|
||||
attach = {
|
||||
self.pool.get( 'ir.attachment' ).create( cr, uid, {
|
||||
'res_id': id,
|
||||
'res_model': model,
|
||||
'name': document.name,
|
||||
'datas': document.datas,
|
||||
'datas_fname': document.name,
|
||||
'description': 'Attached automatically'
|
||||
}
|
||||
self.pool.get( 'ir.attachment' ).create( cr, uid, attach )
|
||||
'description': 'Document attached automatically'
|
||||
})
|
||||
self.write(cr, uid, [document.id], {'state': 'processed'})
|
||||
|
||||
|
||||
def executeAttachs( self, cr, uid, ids ):
|
||||
for document in self.browse( cr, uid, ids ):
|
||||
reference = None
|
||||
if document.template_id:
|
||||
function = document.template_id.attach_function
|
||||
if document.template:
|
||||
function = document.template.attach_function
|
||||
if function:
|
||||
properties = dict( [(x.name, unicode( x.value, 'latin-1' )) for x in document.properties] )
|
||||
|
||||
|
@ -357,6 +389,8 @@ class nan_document_property(osv.osv):
|
|||
_columns = {
|
||||
'name' : fields.char('Text', 256),
|
||||
'value' : fields.char('Value', 256),
|
||||
'document_id' : fields.many2one('nan.document', 'Document', required=True, ondelete='cascade')
|
||||
'document' : fields.many2one('nan.document', 'Document', required=True, ondelete='cascade'),
|
||||
'template_box' : fields.many2one('nan.template.box', 'Template Box', required=True, ondelete='set null')
|
||||
}
|
||||
nan_document_property()
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" ?>
|
||||
<terp>
|
||||
<data>
|
||||
<record model="res.request.link" id="wkf">
|
||||
<field name="name">Document in Queue</field>
|
||||
<field name="object">nan.document</field>
|
||||
</record>
|
||||
</data>
|
||||
</terp>
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
<tree string="Documents in queue">
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
<field name="template_id"/>
|
||||
<field name="template"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -24,16 +24,20 @@
|
|||
<page string="General">
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
<field name="template_id"/>
|
||||
<field name="template"/>
|
||||
<field name="document"/>
|
||||
<separator string="Task"/>
|
||||
<field name="task" nolabel="1" colspan="4"/>
|
||||
<separator string="Image"/>
|
||||
<field name="datas" widget="image" img_width="300" img_height="300" nolabel="1" colspan="4"/>
|
||||
<group colspan="4">
|
||||
<button name="scan_document" states="pending" string="Scan Document"/>
|
||||
<button name="verify_document" states="scanned" string="Verify Document"/>
|
||||
<button name="process_document" states="verified" string="Process Document"/>
|
||||
<button name="scan_document" states="pending" string="Scan document"/>
|
||||
<button name="pending_to_scanning" states="pending" string="Scan document in the background"/>
|
||||
<button name="verify_document" states="scanned" string="Verify document"/>
|
||||
<button name="scanned_to_pending" states="scanned" string="Back to pending"/>
|
||||
<button name="process_document" states="verified" string="Process document"/>
|
||||
<button name="verified_to_processing" states="verified" string="Process document in the background"/>
|
||||
<button name="verified_to_scanned" states="verified" string="Unset verified"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Properties">
|
||||
|
@ -41,10 +45,12 @@
|
|||
<form string="Properties">
|
||||
<field name="name"/>
|
||||
<field name="value"/>
|
||||
<field name="template_box"/>
|
||||
</form>
|
||||
<tree string="Properties">
|
||||
<field name="name"/>
|
||||
<field name="value"/>
|
||||
<field name="template_box"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
|
|
|
@ -12,6 +12,13 @@
|
|||
<field name="wkf_id" ref="wkf"/>
|
||||
<field name="flow_start">True</field>
|
||||
<field name="name">pending</field>
|
||||
<field name="action">write({'state':'pending'})</field>
|
||||
</record>
|
||||
<record model="workflow.activity" id="scanning">
|
||||
<field name="wkf_id" ref="wkf"/>
|
||||
<field name="name">scanning</field>
|
||||
<field name="action">scan_document_background() write({'state':'scanning'})</field>
|
||||
<field name="kind">function</field>
|
||||
</record>
|
||||
<record model="workflow.activity" id="scanned">
|
||||
<field name="wkf_id" ref="wkf"/>
|
||||
|
@ -25,11 +32,17 @@
|
|||
<field name="action">write({'state':'verified'})</field>
|
||||
<field name="kind">function</field>
|
||||
</record>
|
||||
<record model="workflow.activity" id="processing">
|
||||
<field name="wkf_id" ref="wkf"/>
|
||||
<field name="name">processing</field>
|
||||
<field name="action">process_document_background() write({'state':'processing'})</field>
|
||||
<field name="kind">function</field>
|
||||
</record>
|
||||
<record model="workflow.activity" id="processed">
|
||||
<field name="wkf_id" ref="wkf"/>
|
||||
<field name="flow_stop">True</field>
|
||||
<field name="name">processed</field>
|
||||
<field name="action">write({'state':'processed'})</field>
|
||||
<field name="action">process_document() write({'state':'processed'})</field>
|
||||
<field name="kind">function</field>
|
||||
</record>
|
||||
|
||||
|
@ -51,5 +64,37 @@
|
|||
<field name="act_to" ref="processed"/>
|
||||
<field name="signal">process_document</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t4">
|
||||
<field name="act_from" ref="pending"/>
|
||||
<field name="act_to" ref="scanning"/>
|
||||
<field name="signal">pending_to_scanning</field>
|
||||
</record>
|
||||
<record model="workflow.transition" id="t5">
|
||||
<field name="act_from" ref="scanning"/>
|
||||
<field name="act_to" ref="scanned"/>
|
||||
<field name="signal">scanning_to_scanned</field>
|
||||
</record>
|
||||
<record model="workflow.transition" id="t6">
|
||||
<field name="act_from" ref="verified"/>
|
||||
<field name="act_to" ref="processing"/>
|
||||
<field name="signal">verified_to_processing</field>
|
||||
</record>
|
||||
<record model="workflow.transition" id="t7">
|
||||
<field name="act_from" ref="processing"/>
|
||||
<field name="act_to" ref="processed"/>
|
||||
<field name="signal">processing_to_processed</field>
|
||||
</record>
|
||||
|
||||
<record model="workflow.transition" id="t8">
|
||||
<field name="act_from" ref="scanned"/>
|
||||
<field name="act_to" ref="pending"/>
|
||||
<field name="signal">scanned_to_pending</field>
|
||||
</record>
|
||||
<record model="workflow.transition" id="t9">
|
||||
<field name="act_from" ref="verified"/>
|
||||
<field name="act_to" ref="scanned"/>
|
||||
<field name="signal">verified_to_scanned</field>
|
||||
</record>
|
||||
</data>
|
||||
</terp>
|
||||
|
|
Loading…
Reference in New Issue