Skip to content

Commit

Permalink
[RELEASE] 16.0.8.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
SIP authored and SIP committed Apr 4, 2024
1 parent 82de86b commit d56c9ee
Show file tree
Hide file tree
Showing 60 changed files with 1,284 additions and 700 deletions.
13 changes: 12 additions & 1 deletion bad_connector_woocommerce/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
* Submenu of Configurations > WooCommerce Sale Status which is use to store all the WooCommerce Sale Order Status.
* Required field are Location,Client Key,Client Secret.
* 'Test' mode is used to test the environment using test data, while the 'Production' mode is used for the live environment that contains real customer data and requires production-level credentials.
* Create a module named bad_connector_woocommerce This module focuses on the import of "Customers", "Products","Product Attributes","Product Categories", "Taxes", "Orders" and export of "Orders" and its "Refunds" data between connected Woocommerce and Odoo.
* Create a module named bad_connector_woocommerce This module focuses on the import of "Customers", "Products","Product Attributes","Product Categories", "Taxes", "Orders", "Refunds" and export of "Orders" and its "Refunds" data between connected Woocommerce and Odoo.
* Add "Import Partners","Import Products","Import Product Templates","Import Product Attributes","Import Product Category", "Import Orders", "Sync Metadata", "Import Taxes", "Update Stock Inventory" and "Export Refunds" at backend level.
* Required field to Import the Partners,Product Templates,Products,Product Attributes,Taxes,Product Tags,Product Category,Update Stock Inventory, Sale Orders and Export Sale Order Refunds are Location,Client Id,Client Secret,Product Category,Company and Warehouse.
* Add Button of "GENERATE TOKEN" to generate the "Access Token".
* Added multi-warehouse functionality to manages stock.
* Multi company support.

**Author**
**********
Expand Down Expand Up @@ -117,6 +118,11 @@
- Add Backend Credentials to Export Refunds.
- Click 'Export Refunds' button to Export the Refunds to Woocommerce.

* Refunds Import:
- Navigate to Woocommerce Backends by going to Connectors > WooCommerce > WooCommerce Backends.
- Add Backend Credentials to Import Refunds.
- Click 'Import Orders' button to Import the Refunds from Woocommerce.

**Usage**
*********

Expand Down Expand Up @@ -199,6 +205,11 @@
- After confirming the Sale Order, validating the Delivery Order, Creating the Return with its Return Reason, and then validating the Return, there we added a new field called "Refund Quantity With Amount" at the stock.picking level. If the boolean associated with this field is set to True, it allows the export of refunds to WooCommerce by clicking on the "Export Refund" boolean.
- Added "Export Refunds" button at the backend level. This button facilitates the export of all eligible returns for refunds.

* Import of Refunds:
- Enable the Import functionality in bad_connector_woocommerce to transfer Refunds from WooCommerce to Odoo.
- Handle mapping of Refund data during the Import process.
- After Import the Sale Order, Validating the Delivery Order, and Then Click on "Import Order" from Backend Level to import the refunds from WooCommerce.

**Known issues/Roadmap**
************************

Expand Down
1 change: 1 addition & 0 deletions bad_connector_woocommerce/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import components
from . import models
from . import controllers
from . import wizard
2 changes: 1 addition & 1 deletion bad_connector_woocommerce/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Odoo Woocommerce Connector",
"version": "16.0.7.0.0",
"version": "16.0.8.0.0",
"category": "Connector",
"author": "BizzAppDev Systems Pvt. Ltd.",
"website": "http://www.bizzappdev.com",
Expand Down
2 changes: 1 addition & 1 deletion bad_connector_woocommerce/components/backend_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def call(self, resource_path, arguments, http_method=None):
)
status_code = result.status_code
if status_code == 201:
return result
return result.json()
if status_code == 200:
json_response = result.json()
record_count = result.headers.get("X-WP-Total")
Expand Down
94 changes: 35 additions & 59 deletions bad_connector_woocommerce/components/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,12 @@ def __init__(self, work_context):
# the latest status in odoo instead of sending the import request again
self.response_data = None
self.remote_record = None
self.odoo_record = None

def _should_import(self, **kwargs):
if not self.binding:
return True
return False

def create_get_binding(self, record, extra_data=None, **kwargs):
def create_get_binding(self, extra_data=None):
"""Search for the existing binding else create new binding"""
binder = self.binder_for(model=self.model._name)
record = self.odoo_record.with_context(active_test=False)
external_id = False
if self._default_binding_field and record[self._default_binding_field]:
binding = record[self._default_binding_field][:1]
Expand Down Expand Up @@ -84,35 +81,40 @@ def run(self, binding, record=None, fields=None, *args, **kwargs):
Run the synchronization
:param binding: binding record to export
"""
if not binding:
if not record:
raise ValidationError(_("No record found to export!!!"))
binding = self.create_get_binding(record)
if not record and binding:
record = binding.odoo_id

assert record
self.odoo_record = record

self.binding = binding
self.external_id = self.binder.to_external(self.binding)
self._before_export()

# Skip record export if external id exist
skip = self._has_to_skip()
if skip:
return skip
try:
should_import = self._should_import()
except IDMissingInBackend:
self.external_id = None
should_import = False
if should_import:
self._delay_import()
return

return # BAD customization
result = self._run(*args, **kwargs)
if not self.external_id or self.external_id == "False":
self.external_id = record.id
self.binder.bind(self.external_id, self.binding)
# Commit so we keep the external ID when there are several
# exports (due to dependencies) and one of them fails.
# The commit will also release the lock acquired on the binding
# record
if not tools.config["test_enable"]:
self.env.cr.commit() # pylint: disable=E8102
self._after_export(self.binding)

self._after_export()
return result

def _after_export(self, binding):
def _after_export(self):
pass

def _export_dependency(
Expand Down Expand Up @@ -157,49 +159,15 @@ def _export_dependency(
if binding_ids.filtered(
lambda bind: getattr(bind, binder._external_field)
and bind.backend_id == self.backend_record
and bind.external_id not in ["False", "false"]
):
return

if not relation:
return
# wrap is typically True if the relation is for instance a
# 'res.partner' record but the binding model is
# 'my_bakend.res.partner'
wrap = relation._name != binding_model

if wrap and hasattr(relation, binding_field):
domain = [
("odoo_id", "=", relation.id),
("backend_id", "=", self.backend_record.id),
]
binding = self.env[binding_model].search(domain)
if binding:
assert len(binding) == 1, (
"only 1 binding for a backend is " "supported in _export_dependency"
)
# we are working with a unwrapped record (e.g.
# product.category) and the binding does not exist yet.
# Example: I created a product.product and its binding
# my_backend.product.product and we are exporting it, but we need
# to create the binding for the product.category on which it
# depends.
else:
# BAD customization: moved to create_get_binding
with self._retry_unique_violation():
binding = exporter.create_get_binding(
record=relation, extra_data=binding_extra_vals
)
# BAD customization end
if not tools.config["test_enable"]:
self.env.cr.commit() # pylint: disable=E8102
else:
# If my_backend_bind_ids does not exist we are typically in a
# "direct" binding (the binding record is the same record).
# If wrap is True, relation is already a binding record.
binding = relation

if not binder.to_external(binding):
exporter.run(binding)
binding = self.env[binding_model]
exporter.run(binding=binding, record=relation)

def _before_export(self):
pass
Expand All @@ -213,7 +181,7 @@ def _export_dependencies(self, **kwargs):
"""
if not hasattr(self.backend_adapter, "_model_export_dependencies"):
return
record = self.binding.odoo_id
record = self.odoo_record
for dependency in self.backend_adapter._model_export_dependencies:
model, key = dependency
relations = record.mapped(key)
Expand All @@ -225,18 +193,26 @@ def _export_dependencies(self, **kwargs):

def _run(self, fields=None, **kwargs):
"""Flow of the synchronization, implemented in inherited classes"""
assert self.binding

if not self.external_id:
fields = None # should be created with all the fields

self._before_export()
# export the missing linked resources
# Check before calling export dependencies as we need self.odoo_record
if not self.binding and not self.odoo_record:
raise ValidationError(_("No record found to export!!!"))
if not self.odoo_record:
self.odoo_record = self.binding.odoo_id
self._export_dependencies(**kwargs)

# BAD-START To prevent empty bindings, create a binding here.
if not self.binding:
self.binding = self.create_get_binding()

self.external_id = self.binder.to_external(self.binding)

# prevent other jobs to export the same record
# will be released on commit (or rollback)
# self._lock()
self._lock()
map_record = self._map_data(**kwargs)
if self.external_id:
record = self._update_data(map_record, fields=fields, **kwargs)
Expand Down
28 changes: 20 additions & 8 deletions bad_connector_woocommerce/components/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def run(self, external_id, data=None, force=False, **kwargs):
self.remote_record = data
else:
try:
self.remote_record = self._get_remote_data()
self.remote_record = self._get_remote_data(**kwargs)
except IDMissingInBackend:
return _("Record does no longer exist in remote system")

Expand All @@ -278,7 +278,15 @@ def run(self, external_id, data=None, force=False, **kwargs):
else:
record = self._create_data(map_record)
binding = self._create(record)
self.binder.bind(self.external_id, binding)
if len(binding) == 1:
self.binder.bind(self.external_id, binding)
else:
for index, binding_record in enumerate(binding):
if index == 0:
binding_record.external_id = self.external_id
else:
binding_record.external_id = f"{self.external_id}_{index}"
self.binder.bind(binding_record.external_id, binding_record)
self._after_import(binding, **kwargs)


Expand Down Expand Up @@ -339,7 +347,7 @@ def run(self, filters=None, force=None, job_options=None, **kwargs):
job_options=job_options,
force=force,
data=record,
**kwargs
**kwargs,
)
filters["record_count"] += len(records)
record_count = data.get("record_count", 0)
Expand Down Expand Up @@ -367,15 +375,17 @@ def process_next_page(self, filters=None, force=False, job_options=None, **kwarg
)
job_options["description"] = description
if not kwargs.get("no_delay"):
model = model.with_delay(**job_options or {})
model = model.with_company(self.backend_record.company_id).with_delay(
**job_options or {}
)
if "identity_key" in job_options:
job_options.pop("identity_key")
model.import_batch(
self.backend_record,
force=force,
filters=filters,
job_options=job_options,
**kwargs
**kwargs,
)

def _import_record(
Expand All @@ -401,7 +411,7 @@ def _import_record(self, external_id, data=None, force=False, **kwargs):
external_id=external_id,
data=data,
force=force,
**kwargs
**kwargs,
)


Expand All @@ -424,11 +434,13 @@ def _import_record(
model=self.model._description,
)
job_options["description"] = description
delayable = self.model.with_delay(**job_options or {})
delayable = self.model.with_company(self.backend_record.company_id).with_delay(
**job_options or {}
)
delayable.import_record(
backend=self.backend_record,
external_id=external_id,
force=force,
data=data,
**kwargs
**kwargs,
)
12 changes: 12 additions & 0 deletions bad_connector_woocommerce/data/queue_job_data.xml
Original file line number Diff line number Diff line change
Expand Up @@ -416,5 +416,17 @@
<field name="method">export_record</field>
<field name="channel_id" ref="channel_woocommerce" />
</record>
<!-- Import Refund related action queue job -->
<record
id="job_function_woo_import_woo_stock_picking_refund_import_record"
model="queue.job.function"
>
<field
name="model_id"
ref="bad_connector_woocommerce.model_woo_stock_picking_refund"
/>
<field name="method">import_record</field>
<field name="channel_id" ref="channel_woocommerce" />
</record>
</data>
</odoo>
1 change: 1 addition & 0 deletions bad_connector_woocommerce/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
from . import woo_payment_gateway
from . import woo_downloadable_product
from . import stock_picking
from . import stock_move
4 changes: 3 additions & 1 deletion bad_connector_woocommerce/models/product/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ def on_record_write(self, record, fields=None):
description, record._description
)
job_options["priority"] = 20
record.with_delay(**job_options or {}).export_record(
record.with_company(record.backend_id.company_id).with_delay(
**job_options or {}
).export_record(
backend=record.backend_id, record=record, fields=inventory_fields
)
2 changes: 1 addition & 1 deletion bad_connector_woocommerce/models/product/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def _unlink_downloadable_product(self, map_record, product_ids):
product.woo_downloadable_product_ids.mapped("external_id")
)

removable_product = set(product_ids) ^ downloadable_in_record
removable_product = downloadable_in_record - set(product_ids)
if removable_product:
records_to_unlink = self.env["woo.downloadable.product"].search(
[("external_id", "in", list(removable_product))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ def _after_import(self, binding, **kwargs):
model=product_model._description,
)
job_options["description"] = description
delayable = product_model.with_delay(**job_options or {})
delayable = product_model.with_company(
binding.backend_id.company_id
).with_delay(**job_options or {})
delayable.import_record(
backend=self.backend_record, external_id=variant_id, **kwargs
)
Expand Down
7 changes: 7 additions & 0 deletions bad_connector_woocommerce/models/queue_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ def open_related_action(self):
[("external_id", "=", external_id), ("backend_id", "=", backend.id)],
limit=1,
)
if self.model_name == "woo.stock.picking.refund":
record |= self.env[self.model_name].search(
[
("external_id", "ilike", "%s_%%" % external_id),
("backend_id", "=", backend.id),
],
)
else:
record = external_id
if hasattr(record, "odoo_id"):
Expand Down
6 changes: 4 additions & 2 deletions bad_connector_woocommerce/models/sale_order/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def validate_delivery_orders_done(self):
based on delivery order state.
"""
picking_ids = self.mapped("picking_ids").filtered(
lambda p: p.state in ["done", "cancel"]
lambda p: p.state == "done" and p.picking_type_id.code == "outgoing"
)
if not picking_ids:
raise ValidationError(_("No delivery orders in 'done' state."))
Expand All @@ -245,7 +245,9 @@ def update_woo_order_fulfillment_status(self, job_options=None):
job_options["description"] = self.backend_id.get_queue_job_description(
description, self._description
)
woo_model = woo_model.with_delay(**job_options or {})
woo_model = woo_model.with_company(self.backend_id.company_id).with_delay(
**job_options or {}
)
for woo_order in self:
if not self._context.get("execute_from_cron"):
woo_order.validate_delivery_orders_done()
Expand Down
Loading

0 comments on commit d56c9ee

Please sign in to comment.