diff --git a/bemade_packing_wizard/__init__.py b/bemade_packing_wizard/__init__.py
new file mode 100644
index 0000000..3616b30
--- /dev/null
+++ b/bemade_packing_wizard/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+
+from . import models
+from . import wizard
\ No newline at end of file
diff --git a/bemade_packing_wizard/__manifest__.py b/bemade_packing_wizard/__manifest__.py
new file mode 100644
index 0000000..41b136d
--- /dev/null
+++ b/bemade_packing_wizard/__manifest__.py
@@ -0,0 +1,25 @@
+{
+ 'name': 'Packing wizard',
+ 'version': '15.0.1.0.0',
+ 'category': 'Extra Tools',
+ 'summary': 'Allow automated packing type creation',
+ 'description': """
+ This module allows users simply enter all the package dimensions on every packing and it will create the packing
+ type automatically if it not exists, use it the create the package with the weight and related package type.
+
+ You need to activate the auto create package feature on the delivery carrier to use this feature.
+ """,
+ 'depends': [
+ 'delivery'
+ ],
+ 'data': [
+ 'views/stock_package_views.xml',
+ 'views/delivery_carrier_views.xml',
+ 'wizard/choose_delivery_package_views.xml',
+ ],
+ 'license': 'AGPL-3',
+ 'author': 'Bemade',
+ 'website': 'https://bemade.org/',
+ 'installable': True,
+ 'auto_install': False
+}
diff --git a/bemade_packing_wizard/models/__init__.py b/bemade_packing_wizard/models/__init__.py
new file mode 100644
index 0000000..aea7c24
--- /dev/null
+++ b/bemade_packing_wizard/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+from . import stock_quant_package
+from . import delivery_carrier
+
diff --git a/bemade_packing_wizard/models/delivery_carrier.py b/bemade_packing_wizard/models/delivery_carrier.py
new file mode 100644
index 0000000..4f72762
--- /dev/null
+++ b/bemade_packing_wizard/models/delivery_carrier.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+
+from odoo import models, fields, api
+from odoo.exceptions import ValidationError
+
+class DeliveryCarrier(models.Model):
+ _inherit = 'delivery.carrier'
+
+ # this allow us to enable the auto create package feature per delivery.carrier
+ # default is False to avoid impacting Odoo's default behavior on Test
+ auto_create_package = fields.Boolean('Auto Create Package', default=False)
\ No newline at end of file
diff --git a/bemade_packing_wizard/models/stock_quant_package.py b/bemade_packing_wizard/models/stock_quant_package.py
new file mode 100644
index 0000000..fc4ce1f
--- /dev/null
+++ b/bemade_packing_wizard/models/stock_quant_package.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+
+from odoo import models, fields, api
+from odoo.exceptions import ValidationError
+
+class StockQuantPackage(models.Model):
+ _inherit = 'stock.quant.package'
+
+ length = fields.Float('Length')
+ width = fields.Float('Width')
+ height = fields.Float('Height')
+
+ carrier_id = fields.Many2one(
+ comodel_name='delivery.carrier',
+ string='Carrier',
+ help="Carrier use to create package.",
+ compute='_compute_package_carrier'
+ )
+
+ provider = fields.Selection(
+ selection=lambda self: self._get_provider(),
+ string='Provider',
+ help="Provider to create package.",
+ compute='_compute_package_carrier'
+ )
+
+ auto_create_package = fields.Boolean(
+ string='Auto Create Package',
+ compute='_compute_auto_create_package'
+ )
+
+
+ @api.depends('carrier_id')
+ def _compute_auto_create_package(self):
+ for record in self:
+ record.auto_create_package = record.carrier_id.auto_create_package if record.carrier_id else False
+
+
+ def _compute_package_carrier(self):
+ move_line = self.env['stock.move.line'].search([('result_package_id', '=', self.id)])
+ self.carrier_id = move_line.carrier_id
+ delivery_types_available = [item[0] for item in self.env['stock.package.type']._fields['package_carrier_type'].selection]
+ if self.carrier_id.delivery_type not in delivery_types_available:
+ self.provider = False
+ else:
+ self.provider = move_line.carrier_id.delivery_type
+
+
+ def _get_package_carrier_types(self):
+ return self.env['stock.package.type']._fields['package_carrier_type'].selection
+
+
+ def _get_provider(self):
+ return self.env['stock.package.type']._fields['package_carrier_type'].selection
+
+
+ def write(self, vals):
+ if 'length' in vals and 'width' in vals and 'height' in vals:
+ # check if length, width, height are greater than 0
+ if vals['length'] <= 0 or vals['width'] <= 0 or vals['height'] <= 0:
+ raise ValidationError('Length, width, and height must be greater than 0.')
+ # Make sure length is always greater than width
+ if vals['length'] < vals['width']:
+ vals['length'], vals['width'] = vals['width'], vals['length']
+ # check if existing package_type exists
+ package_type = self.env['stock.package.type'].search([
+ ('width', '=', vals['width']),
+ ('height', '=', vals['height']),
+ ('packaging_length', '=', vals['length']),
+ ('package_carrier_type', '=', self.provider)
+ ], limit=1)
+# ])
+
+ if not package_type:
+ package_type = self.env['stock.package.type'].create({
+ 'name': f'Box {vals["width"]}x{vals["height"]}x{vals["length"]}',
+ 'width': vals['width'],
+ 'height': vals['height'],
+ 'packaging_length': vals['length'],
+ 'package_carrier_type': self.provider
+ })
+
+ vals['package_type_id'] = package_type.id
+
+ res = super(StockQuantPackage, self).write(vals)
+
+ # check if length, width, height are changed
+ return res
\ No newline at end of file
diff --git a/bemade_packing_wizard/views/delivery_carrier_views.xml b/bemade_packing_wizard/views/delivery_carrier_views.xml
new file mode 100644
index 0000000..ab68008
--- /dev/null
+++ b/bemade_packing_wizard/views/delivery_carrier_views.xml
@@ -0,0 +1,13 @@
+
+
+
+ Auto package configuration
+ delivery.carrier
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bemade_packing_wizard/views/stock_package_views.xml b/bemade_packing_wizard/views/stock_package_views.xml
new file mode 100644
index 0000000..8210b1d
--- /dev/null
+++ b/bemade_packing_wizard/views/stock_package_views.xml
@@ -0,0 +1,20 @@
+
+
+
+ stock.view_quant_package_form_size
+ stock.quant.package
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bemade_packing_wizard/wizard/__init__.py b/bemade_packing_wizard/wizard/__init__.py
new file mode 100644
index 0000000..06b962d
--- /dev/null
+++ b/bemade_packing_wizard/wizard/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+from . import choose_delivery_package
diff --git a/bemade_packing_wizard/wizard/choose_delivery_package.py b/bemade_packing_wizard/wizard/choose_delivery_package.py
new file mode 100644
index 0000000..75d1658
--- /dev/null
+++ b/bemade_packing_wizard/wizard/choose_delivery_package.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+from odoo import models, fields, api
+from math import ceil
+from odoo.exceptions import ValidationError
+
+
+class ChooseDeliveryPackage(models.TransientModel):
+ _inherit = 'choose.delivery.package'
+
+ length = fields.Float('Length')
+ width = fields.Float('Width')
+ height = fields.Float('Height')
+
+ auto_create_package = fields.Boolean(
+ string='Auto Create Package',
+ )
+
+ provider = fields.Selection(
+ selection=lambda self: self._get_provider(),
+ string='Provider',
+ help="Provider to create package.",
+ )
+
+ @api.model
+ def default_get(self, fields_list):
+ defaults = super().default_get(fields_list)
+ if 'provider' in fields_list:
+ picking = self.env['stock.picking'].browse(defaults.get('picking_id'))
+
+ delivery_types_available = [item[0] for item in self.env['stock.package.type']._fields['package_carrier_type'].selection]
+ if picking.carrier_id.delivery_type not in delivery_types_available:
+ defaults['provider'] = False
+ defaults['auto_create_package'] = False
+ else:
+ defaults['provider'] = picking.carrier_id.delivery_type
+ defaults['auto_create_package'] = picking.carrier_id.auto_create_package
+ return defaults
+
+
+ def _get_provider(self):
+ return self.env['stock.package.type']._fields['package_carrier_type'].selection
+
+ # def _compute_auto_create_package(self):
+ # for record in self:
+ # record.auto_create_package = record.carrier_id.auto_create_package if record.carrier_id else False
+ #
+ # def _compute_provider(self):
+ # move_line = self.env['stock.move.line'].search([('result_package_id', '=', self.id)])
+ # delivery_types_available = [item[0] for item in self.env['stock.package.type']._fields['package_carrier_type'].selection]
+ # if self.picking_id.carrier_id.delivery_type not in delivery_types_available:
+ # self.provider = False
+ # else:
+ # self.provider = move_line.carrier_id.delivery_type
+ #
+
+
+ def action_put_in_pack(self):
+ if self.auto_create_package:
+ if self.width <= 0 or self.height <= 0 or self.length <= 0:
+ raise ValidationError('Length, width, and height must be greater than 0.')
+
+ if self.length < self.width:
+ self.length, self.width = self.width, self.length
+
+ delivery_package_type = self.env['stock.package.type'].search([
+ ('width', '=', self.width),
+ ('height', '=', self.height),
+ ('packaging_length', '=', self.length),
+ ('package_carrier_type', '=', self.provider)
+ ], limit=1)
+
+ if not delivery_package_type:
+ delivery_package_type = delivery_package_type.create({
+ 'name': f'Box {vals["width"]}x{vals["height"]}x{vals["length"]}',
+ 'width': self.width,
+ 'height': self.height,
+ 'packaging_length': self.length,
+ 'package_carrier_type': self.provider
+ })
+
+ self.delivery_package_type_id = delivery_package_type.id
+ result = super().action_put_in_pack()
+ return result
\ No newline at end of file
diff --git a/bemade_packing_wizard/wizard/choose_delivery_package_views.xml b/bemade_packing_wizard/wizard/choose_delivery_package_views.xml
new file mode 100644
index 0000000..ea9654b
--- /dev/null
+++ b/bemade_packing_wizard/wizard/choose_delivery_package_views.xml
@@ -0,0 +1,23 @@
+
+
+
+ choose.delivery.package.form2
+ choose.delivery.package
+
+
+
+
+
+
+
+
+
+
+
+
+
+