Split 49 modules/suites into independent git repos; untrack from monorepo
Each top-level module/suite folder is now its own private repo on GitHub (gsinghpal/<name>) and gitea (admin/<name>), with a fresh single initial commit. The monorepo no longer tracks them (added to .gitignore + git rm --cached); working-tree files are retained on disk and managed in their own repos. The monorepo keeps shared root files (CLAUDE.md, docs/, scripts/, tools/, AGENTS.md, WIP/obsolete dirs) and full history. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,297 +0,0 @@
|
||||
import base64
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WooOrder(models.Model):
|
||||
_name = 'woo.order'
|
||||
_description = 'WooCommerce Order'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_rec_name = 'display_name'
|
||||
_order = 'id desc'
|
||||
|
||||
display_name = fields.Char(compute='_compute_display_name', store=True)
|
||||
instance_id = fields.Many2one('woo.instance', required=True, ondelete='cascade')
|
||||
sale_order_id = fields.Many2one('sale.order')
|
||||
woo_order_id = fields.Integer(index=True)
|
||||
woo_order_number = fields.Char(string='WC Order #')
|
||||
woo_status = fields.Selection([
|
||||
('pending', 'Pending Payment'),
|
||||
('processing', 'Processing'),
|
||||
('on-hold', 'On Hold'),
|
||||
('completed', 'Completed'),
|
||||
('cancelled', 'Cancelled'),
|
||||
('refunded', 'Refunded'),
|
||||
('failed', 'Failed'),
|
||||
('trash', 'Trashed'),
|
||||
], string='WC Status', tracking=True)
|
||||
invoice_id = fields.Many2one('account.move')
|
||||
invoice_synced = fields.Boolean()
|
||||
company_id = fields.Many2one(
|
||||
'res.company', required=True, default=lambda self: self.env.company,
|
||||
)
|
||||
state = fields.Selection([
|
||||
('new', 'New'),
|
||||
('confirmed', 'Confirmed'),
|
||||
('shipped', 'Shipped'),
|
||||
('completed', 'Completed'),
|
||||
('cancelled', 'Cancelled'),
|
||||
], default='new', tracking=True)
|
||||
|
||||
WC_STATUS_TO_STATE = {
|
||||
'pending': 'new',
|
||||
'on-hold': 'new',
|
||||
'processing': 'confirmed',
|
||||
'completed': 'completed',
|
||||
'cancelled': 'cancelled',
|
||||
'refunded': 'cancelled',
|
||||
'failed': 'cancelled',
|
||||
'trash': 'cancelled',
|
||||
}
|
||||
|
||||
@api.onchange('woo_status')
|
||||
def _onchange_woo_status(self):
|
||||
if self.woo_status:
|
||||
self.state = self.WC_STATUS_TO_STATE.get(self.woo_status, self.state)
|
||||
|
||||
def _set_woo_status(self, wc_status):
|
||||
"""Set woo_status and auto-map to Odoo state."""
|
||||
vals = {}
|
||||
if wc_status:
|
||||
vals['woo_status'] = wc_status
|
||||
mapped_state = self.WC_STATUS_TO_STATE.get(wc_status)
|
||||
if mapped_state:
|
||||
vals['state'] = mapped_state
|
||||
if vals:
|
||||
self.write(vals)
|
||||
shipment_ids = fields.One2many('woo.shipment', 'order_id')
|
||||
|
||||
delivery_count = fields.Integer(compute='_compute_delivery_count')
|
||||
invoice_count = fields.Integer(compute='_compute_invoice_count')
|
||||
|
||||
@api.depends('woo_order_number', 'sale_order_id', 'sale_order_id.name')
|
||||
def _compute_display_name(self):
|
||||
for rec in self:
|
||||
parts = []
|
||||
if rec.woo_order_number:
|
||||
parts.append('WC#%s' % rec.woo_order_number)
|
||||
if rec.sale_order_id:
|
||||
parts.append(rec.sale_order_id.name)
|
||||
rec.display_name = ' — '.join(parts) if parts else 'WC Order #%s' % rec.id
|
||||
|
||||
@api.depends('sale_order_id')
|
||||
def _compute_delivery_count(self):
|
||||
for rec in self:
|
||||
if rec.sale_order_id:
|
||||
rec.delivery_count = self.env['stock.picking'].search_count([
|
||||
('origin', '=', rec.sale_order_id.name),
|
||||
])
|
||||
else:
|
||||
rec.delivery_count = 0
|
||||
|
||||
@api.depends('sale_order_id')
|
||||
def _compute_invoice_count(self):
|
||||
for rec in self:
|
||||
if rec.sale_order_id:
|
||||
rec.invoice_count = self.env['account.move'].search_count([
|
||||
('invoice_origin', '=', rec.sale_order_id.name),
|
||||
('move_type', 'in', ['out_invoice', 'out_refund']),
|
||||
])
|
||||
else:
|
||||
rec.invoice_count = 0
|
||||
|
||||
def action_view_sale_order(self):
|
||||
self.ensure_one()
|
||||
if not self.sale_order_id:
|
||||
return
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'sale.order',
|
||||
'res_id': self.sale_order_id.id,
|
||||
'views': [(False, 'form')],
|
||||
}
|
||||
|
||||
def action_view_deliveries(self):
|
||||
self.ensure_one()
|
||||
pickings = self.env['stock.picking'].search([
|
||||
('origin', '=', self.sale_order_id.name),
|
||||
])
|
||||
if len(pickings) == 1:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'stock.picking',
|
||||
'res_id': pickings.id,
|
||||
'views': [(False, 'form')],
|
||||
}
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Deliveries',
|
||||
'res_model': 'stock.picking',
|
||||
'view_mode': 'list,form',
|
||||
'domain': [('origin', '=', self.sale_order_id.name)],
|
||||
}
|
||||
|
||||
def action_view_invoices(self):
|
||||
self.ensure_one()
|
||||
invoices = self.env['account.move'].search([
|
||||
('invoice_origin', '=', self.sale_order_id.name),
|
||||
('move_type', 'in', ['out_invoice', 'out_refund']),
|
||||
])
|
||||
if len(invoices) == 1:
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'account.move',
|
||||
'res_id': invoices.id,
|
||||
'views': [(False, 'form')],
|
||||
}
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Invoices',
|
||||
'res_model': 'account.move',
|
||||
'view_mode': 'list,form',
|
||||
'domain': [('invoice_origin', '=', self.sale_order_id.name),
|
||||
('move_type', 'in', ['out_invoice', 'out_refund'])],
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Push methods (Task 20)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def action_push_shipping(self, tracking_number, carrier_id=False):
|
||||
"""Push shipping/tracking info to WooCommerce and update status."""
|
||||
self.ensure_one()
|
||||
client = self.instance_id._get_client()
|
||||
|
||||
update_data = {
|
||||
'status': 'completed',
|
||||
}
|
||||
|
||||
# Build tracking meta
|
||||
meta = [
|
||||
{'key': '_tracking_number', 'value': tracking_number},
|
||||
]
|
||||
if carrier_id:
|
||||
carrier = self.env['woo.shipping.carrier'].browse(carrier_id)
|
||||
if carrier.exists():
|
||||
meta.append({'key': '_tracking_provider', 'value': carrier.name})
|
||||
if carrier.tracking_url:
|
||||
url = carrier.tracking_url.replace('{tracking}', tracking_number)
|
||||
meta.append({'key': '_tracking_url', 'value': url})
|
||||
|
||||
update_data['meta_data'] = meta
|
||||
|
||||
client.update_order(self.woo_order_id, update_data)
|
||||
self._set_woo_status('completed')
|
||||
self.state = 'shipped'
|
||||
|
||||
self.instance_id._log_sync(
|
||||
'order', 'odoo_to_woo', self.sale_order_id.name,
|
||||
'success', f'Shipping pushed with tracking: {tracking_number}',
|
||||
)
|
||||
|
||||
def action_push_completed(self):
|
||||
"""Mark WC order as completed."""
|
||||
self.ensure_one()
|
||||
client = self.instance_id._get_client()
|
||||
client.update_order(self.woo_order_id, {'status': 'completed'})
|
||||
self._set_woo_status('completed')
|
||||
|
||||
self.instance_id._log_sync(
|
||||
'order', 'odoo_to_woo', self.sale_order_id.name,
|
||||
'success', 'Order marked as completed in WC',
|
||||
)
|
||||
|
||||
def action_push_invoice_pdf(self):
|
||||
"""Render invoice PDF and push to WC via custom plugin endpoint."""
|
||||
self.ensure_one()
|
||||
if not self.invoice_id:
|
||||
raise UserError("No invoice linked to this WC order.")
|
||||
|
||||
# Generate PDF report
|
||||
report = self.env.ref('account.account_invoices')
|
||||
pdf_content, _content_type = report._render_qweb_pdf(
|
||||
report.id, [self.invoice_id.id]
|
||||
)
|
||||
pdf_b64 = base64.b64encode(pdf_content).decode('utf-8')
|
||||
|
||||
# Push to WC via order note or meta
|
||||
try:
|
||||
client = self.instance_id._get_client()
|
||||
client.update_order(self.woo_order_id, {
|
||||
'meta_data': [
|
||||
{'key': '_odoo_invoice_ref', 'value': self.invoice_id.name},
|
||||
{'key': '_odoo_invoice_pdf', 'value': pdf_b64},
|
||||
]
|
||||
})
|
||||
self.invoice_synced = True
|
||||
self.instance_id._log_sync(
|
||||
'invoice', 'odoo_to_woo', self.invoice_id.name,
|
||||
'success', 'Invoice PDF pushed to WC',
|
||||
)
|
||||
except Exception as e:
|
||||
_logger.error("Failed to push invoice PDF to WC: %s", e)
|
||||
self.instance_id._log_sync(
|
||||
'invoice', 'odoo_to_woo', self.invoice_id.name,
|
||||
'failed', str(e),
|
||||
)
|
||||
raise
|
||||
|
||||
def action_push_delivery_pdf(self, picking):
|
||||
"""Render delivery slip PDF and push to WC."""
|
||||
self.ensure_one()
|
||||
report = self.env.ref('stock.action_report_delivery')
|
||||
pdf_content, _content_type = report._render_qweb_pdf(
|
||||
report.id, [picking.id]
|
||||
)
|
||||
pdf_b64 = base64.b64encode(pdf_content).decode('utf-8')
|
||||
|
||||
try:
|
||||
client = self.instance_id._get_client()
|
||||
client.update_order(self.woo_order_id, {
|
||||
'meta_data': [
|
||||
{'key': '_odoo_delivery_ref', 'value': picking.name},
|
||||
{'key': '_odoo_delivery_pdf', 'value': pdf_b64},
|
||||
]
|
||||
})
|
||||
self.instance_id._log_sync(
|
||||
'order', 'odoo_to_woo', picking.name,
|
||||
'success', 'Delivery PDF pushed to WC',
|
||||
)
|
||||
except Exception as e:
|
||||
_logger.error("Failed to push delivery PDF to WC: %s", e)
|
||||
|
||||
def _push_messages_to_wc(self):
|
||||
"""Extract customer-visible messages and push as WC order notes."""
|
||||
self.ensure_one()
|
||||
if not self.sale_order_id:
|
||||
return
|
||||
|
||||
client = self.instance_id._get_client()
|
||||
|
||||
# Get messages from the sale order that are customer-visible
|
||||
messages = self.env['mail.message'].search([
|
||||
('res_id', '=', self.sale_order_id.id),
|
||||
('model', '=', 'sale.order'),
|
||||
('message_type', 'in', ['comment', 'email']),
|
||||
('subtype_id.internal', '=', False),
|
||||
], order='create_date asc')
|
||||
|
||||
for msg in messages:
|
||||
note_body = msg.body or msg.preview or ''
|
||||
if not note_body:
|
||||
continue
|
||||
try:
|
||||
# WC order notes endpoint
|
||||
client.post(f'orders/{self.woo_order_id}/notes', {
|
||||
'note': note_body,
|
||||
'customer_note': True,
|
||||
})
|
||||
except Exception as e:
|
||||
_logger.warning(
|
||||
"Failed to push message to WC order %s: %s",
|
||||
self.woo_order_id, e,
|
||||
)
|
||||
Reference in New Issue
Block a user