diff --git a/modules/automation/__init__.py b/modules/automation/__init__.py
index 58b9658..308bd5e 100644
--- a/modules/automation/__init__.py
+++ b/modules/automation/__init__.py
@@ -1,11 +1,12 @@
-from trytond.pool import Pool
-from . import automation,rules,freight_booking,cron #, document
-
-def register():
- Pool.register(
- automation.AutomationDocument,
- rules.AutomationRuleSet,
- freight_booking.FreightBookingInfo,
- cron.Cron,
- cron.AutomationCron,
- module='automation', type_='model')
\ No newline at end of file
+from trytond.pool import Pool
+from . import automation,rules,freight_booking,booking_report,cron #, document
+
+def register():
+ Pool.register(
+ automation.AutomationDocument,
+ rules.AutomationRuleSet,
+ freight_booking.FreightBookingInfo,
+ booking_report.FreightBookingShipmentReport,
+ cron.Cron,
+ cron.AutomationCron,
+ module='automation', type_='model')
diff --git a/modules/automation/booking_report.py b/modules/automation/booking_report.py
new file mode 100644
index 0000000..2475ef2
--- /dev/null
+++ b/modules/automation/booking_report.py
@@ -0,0 +1,128 @@
+import json
+
+from sql import Literal, Null
+from sql.functions import CurrentTimestamp
+
+from trytond.model import ModelSQL, ModelView, fields
+from trytond.pool import Pool
+
+
+class FreightBookingShipmentReport(ModelSQL, ModelView):
+ "Freight Booking Shipment Report"
+ __name__ = 'freight.booking.shipment.report'
+
+ automation_document = fields.Many2One(
+ 'automation.document', "Automation Document")
+ bl_number = fields.Function(fields.Char("BL Number"), 'get_bl_number')
+ shipment = fields.Function(fields.Many2One(
+ 'stock.shipment.in', "Shipment"), 'get_shipment')
+ status = fields.Function(fields.Selection([
+ ('found', "Found"),
+ ('error', "Error"),
+ ], "Status"), 'get_status')
+
+ @classmethod
+ def __setup__(cls):
+ super().__setup__()
+ cls._order = [
+ ('id', 'DESC'),
+ ]
+
+ @classmethod
+ def table_query(cls):
+ AutomationDocument = Pool().get('automation.document')
+ document = AutomationDocument.__table__()
+
+ return document.select(
+ Literal(None).as_('create_uid'),
+ CurrentTimestamp().as_('create_date'),
+ Literal(None).as_('write_uid'),
+ Literal(None).as_('write_date'),
+ document.id.as_('id'),
+ document.id.as_('automation_document'),
+ where=(
+ (document.type == 'weight_report')
+ & (document.metadata_json != Null)))
+
+ @classmethod
+ def _extract_bl_number(cls, metadata_json):
+ if not metadata_json:
+ return None
+ try:
+ metadata = json.loads(str(metadata_json))
+ except (TypeError, ValueError):
+ return None
+
+ def find_value(value):
+ if isinstance(value, dict):
+ for key in (
+ 'bl_no', 'bl_number', 'bl', 'BL_Number',
+ 'BL number', 'B/L No'):
+ bl_number = value.get(key)
+ if bl_number:
+ return str(bl_number).strip()
+ for item in value.values():
+ bl_number = find_value(item)
+ if bl_number:
+ return bl_number
+ elif isinstance(value, list):
+ for item in value:
+ bl_number = find_value(item)
+ if bl_number:
+ return bl_number
+ return None
+
+ return find_value(metadata)
+
+ @classmethod
+ def _get_report_data(cls, reports):
+ ShipmentIn = Pool().get('stock.shipment.in')
+ bl_numbers = {}
+
+ for report in reports:
+ document = report.automation_document
+ bl_number = cls._extract_bl_number(
+ document.metadata_json if document else None)
+ bl_numbers[report.id] = bl_number
+
+ shipments_by_bl = {}
+ for bl_number in {b for b in bl_numbers.values() if b}:
+ shipments = ShipmentIn.search([
+ ('bl_number', '=', bl_number),
+ ], limit=1)
+ if not shipments:
+ shipments = ShipmentIn.search([
+ ('bl_number', 'ilike', bl_number),
+ ], limit=1)
+ shipments_by_bl[bl_number] = shipments[0] if shipments else None
+
+ return bl_numbers, shipments_by_bl
+
+ @classmethod
+ def get_bl_number(cls, reports, name):
+ bl_numbers, _ = cls._get_report_data(reports)
+ return bl_numbers
+
+ @classmethod
+ def get_shipment(cls, reports, name):
+ bl_numbers, shipments_by_bl = cls._get_report_data(reports)
+ return {
+ report.id: (
+ shipments_by_bl[bl_numbers[report.id]].id
+ if bl_numbers[report.id]
+ and shipments_by_bl.get(bl_numbers[report.id])
+ else None)
+ for report in reports
+ }
+
+ @classmethod
+ def get_status(cls, reports, name):
+ bl_numbers, shipments_by_bl = cls._get_report_data(reports)
+ return {
+ report.id: (
+ 'found'
+ if bl_numbers[report.id]
+ and shipments_by_bl.get(bl_numbers[report.id])
+ else 'error')
+ for report in reports
+ }
diff --git a/modules/automation/booking_report.xml b/modules/automation/booking_report.xml
new file mode 100644
index 0000000..df857de
--- /dev/null
+++ b/modules/automation/booking_report.xml
@@ -0,0 +1,43 @@
+
+