Customer Shipment Autopack

I am using a first draft for an extended Customer Shipment pack transition,
which auto-packs according to rules in the Autopack Model.

For me it is fast enough, but probably too hacky and probably does not really respect the Workflow of Shipment for inclusion in Tryton. (Thus posted in Message Board rather than Feature).
If someone thinks this Model has potential, I will be more than happy to contribute my best for inclusion.
The issue for me has always been that SAO on my mobile device is not adequate to use in the warehouse,
so I end up creating all the labels in the office, then I go out and Pick → Pack → Stick the labels on the boxes.

This hack helps me speed up my workflow for carriers/customers who have a well defined packing.

from trytond.model import ModelSQL, ModelView, Workflow, fields
from trytond.model import MatchMixin,sequence_ordered
from trytond.pool import Pool, PoolMeta

class Autopack(ModelSQL, ModelView, sequence_ordered(), MatchMixin):
    __name__ = 'stock.package.autopack'

    # Match Outgoing Moves
    product = fields.Many2One(
        'product.product', "Product", required=True)
    carrier = fields.Many2One('carrier', "Carrier")
    party = fields.Many2One('party.party', "Party")

    # and pack them according to
    package = fields.Many2One(
        'stock.package.type', "Package", required=True)
    quantity = fields.Float(
        "Quantity", digits='unit', required=True,
        domain=[('quantity', '>', 0)])
    unit = fields.Function(
        fields.Many2One('product.uom', "Unit"),
        'on_change_with_unit')

    @fields.depends('product')
    def on_change_with_unit(self, name=None):
        if self.product:
            return self.product.template.default_uom
        return None

class ShipmentOut(metaclass=PoolMeta):
    __name__ = 'stock.shipment.out'

    @classmethod
    @ModelView.button
    @Workflow.transition('packed')
    def pack(cls, shipments):
        pool = Pool()
        Package = pool.get('stock.package')
        Autopack = pool.get('stock.package.autopack')
        autopacks = Autopack.search([])
        for shipment in shipments:
            to_pack = []
            for move in list(shipment.outgoing_moves):
                if move.state == 'cancelled' or move.package:
                    continue
                pattern = {
                    'product': move.product.id,
                    'party': shipment.customer,
                    'carrier': (
                        shipment.carrier.id
                        if getattr(shipment, 'carrier', None) else None),
                    }
                for autopack in autopacks:
                    if not autopack.match(pattern):
                        continue
                    pieces = move.split(
                        autopack.quantity, move.product.default_uom)
                    to_pack.extend(
                        (piece, autopack.package) for piece in pieces)
                    break
            for move, package_type in to_pack:
                package = Package(
                    company=shipment.company,
                    shipment=shipment,
                    type=package_type,
                    moves=[move],
                )
                package.save()
        super().pack(shipments)