changes
This commit is contained in:
@@ -1141,22 +1141,6 @@ class SaleOrder(models.Model):
|
||||
default=2,
|
||||
help='Page number in approval form where signature should be placed (1-indexed)',
|
||||
)
|
||||
x_fc_sa_signature_position = fields.Selection([
|
||||
('default', 'Default (SA Mobility Standard)'),
|
||||
('middle', 'Middle of Page'),
|
||||
('bottom', 'Bottom of Page'),
|
||||
('custom', 'Custom Position'),
|
||||
], string='Signature Position', default='default')
|
||||
x_fc_sa_signature_offset_x = fields.Integer(
|
||||
string='Signature X Offset',
|
||||
default=0,
|
||||
help='Horizontal offset in points (positive = right)',
|
||||
)
|
||||
x_fc_sa_signature_offset_y = fields.Integer(
|
||||
string='Signature Y Offset',
|
||||
default=0,
|
||||
help='Vertical offset in points (positive = up)',
|
||||
)
|
||||
|
||||
# --- Ontario Works document fields ---
|
||||
x_fc_ow_discretionary_form = fields.Binary(
|
||||
@@ -1593,48 +1577,12 @@ class SaleOrder(models.Model):
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def _get_sa_pdf_template(self):
|
||||
"""Find the active SA Mobility signature template."""
|
||||
return self.env['fusion.sa.signature.template'].search([
|
||||
('active', '=', True),
|
||||
], limit=1)
|
||||
|
||||
def _get_sa_signature_coordinates(self, page_h=792):
|
||||
"""Get signature overlay coordinates.
|
||||
|
||||
Reads the global template from Configuration > PDF Templates,
|
||||
then applies any per-case offsets stored on this sale order.
|
||||
"""
|
||||
self.ensure_one()
|
||||
tpl = self._get_sa_pdf_template()
|
||||
ox = self.x_fc_sa_signature_offset_x or 0
|
||||
oy = self.x_fc_sa_signature_offset_y or 0
|
||||
|
||||
if tpl:
|
||||
coords = tpl.get_sa_coordinates(page_h)
|
||||
else:
|
||||
coords = {
|
||||
'name_x': 105, 'name_y': page_h - 97,
|
||||
'date_x': 430, 'date_y': page_h - 97,
|
||||
'sig_x': 72, 'sig_y': page_h - 72 - 25,
|
||||
'sig_w': 190, 'sig_h': 25,
|
||||
}
|
||||
|
||||
if ox or oy:
|
||||
coords = {
|
||||
'name_x': coords['name_x'] + ox,
|
||||
'name_y': coords['name_y'] + oy,
|
||||
'date_x': coords['date_x'] + ox,
|
||||
'date_y': coords['date_y'] + oy,
|
||||
'sig_x': coords['sig_x'] + ox,
|
||||
'sig_y': coords['sig_y'] + oy,
|
||||
'sig_w': coords['sig_w'],
|
||||
'sig_h': coords['sig_h'],
|
||||
}
|
||||
return coords
|
||||
|
||||
def _apply_pod_signature_to_approval_form(self):
|
||||
"""Auto-overlay POD signature onto the ODSP approval form at the configured page/position."""
|
||||
"""Auto-overlay POD signature onto the ODSP approval form.
|
||||
|
||||
Uses the ODSP PDF Template (fusion.pdf.template, category=odsp) for
|
||||
field positions, and the per-case signature page number.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if not all([
|
||||
self.x_fc_odsp_division == 'sa_mobility',
|
||||
@@ -1645,71 +1593,54 @@ class SaleOrder(models.Model):
|
||||
return
|
||||
|
||||
import base64
|
||||
from io import BytesIO
|
||||
try:
|
||||
from reportlab.pdfgen import canvas as rl_canvas
|
||||
from reportlab.lib.utils import ImageReader
|
||||
from odoo.tools.pdf import PdfFileReader, PdfFileWriter
|
||||
except ImportError:
|
||||
_logger.warning("PDF libraries not available for approval form signing.")
|
||||
from odoo.addons.fusion_authorizer_portal.utils.pdf_filler import PDFTemplateFiller
|
||||
|
||||
tpl = self.env['fusion.pdf.template'].search([
|
||||
('category', '=', 'odsp'), ('state', '=', 'active'),
|
||||
], limit=1)
|
||||
if not tpl:
|
||||
_logger.warning("No active ODSP PDF template found for signing %s", self.name)
|
||||
return
|
||||
|
||||
sig_page = self.x_fc_sa_signature_page or 2
|
||||
|
||||
fields_by_page = {}
|
||||
for field in tpl.field_ids.filtered(lambda f: f.is_active):
|
||||
page = sig_page
|
||||
if page not in fields_by_page:
|
||||
fields_by_page[page] = []
|
||||
fields_by_page[page].append({
|
||||
'field_name': field.name,
|
||||
'field_key': field.field_key or field.name,
|
||||
'pos_x': field.pos_x,
|
||||
'pos_y': field.pos_y,
|
||||
'width': field.width,
|
||||
'height': field.height,
|
||||
'field_type': field.field_type,
|
||||
'font_size': field.font_size,
|
||||
'font_name': field.font_name or 'Helvetica',
|
||||
'text_align': field.text_align or 'left',
|
||||
})
|
||||
|
||||
client_name = self.x_fc_pod_client_name or self.x_fc_sa_client_name or self.partner_id.name or ''
|
||||
sign_date = self.x_fc_pod_signature_date or self.x_fc_sa_client_signed_date
|
||||
context_data = {
|
||||
'sa_client_name': client_name,
|
||||
'sa_sign_date': sign_date.strftime('%b %d, %Y') if sign_date else '',
|
||||
}
|
||||
signatures = {
|
||||
'sa_signature': base64.b64decode(self.x_fc_pod_signature),
|
||||
}
|
||||
|
||||
pdf_bytes = base64.b64decode(self.x_fc_sa_approval_form)
|
||||
original = PdfFileReader(BytesIO(pdf_bytes))
|
||||
output = PdfFileWriter()
|
||||
num_pages = original.getNumPages()
|
||||
target_page = (self.x_fc_sa_signature_page or 2) - 1
|
||||
|
||||
if target_page < 0 or target_page >= num_pages:
|
||||
_logger.warning(
|
||||
"Signature page %s out of range (total %s) for %s",
|
||||
self.x_fc_sa_signature_page, num_pages, self.name
|
||||
try:
|
||||
signed_pdf = PDFTemplateFiller.fill_template(
|
||||
pdf_bytes, fields_by_page, context_data, signatures,
|
||||
)
|
||||
except Exception as e:
|
||||
_logger.error("Failed to apply signature to approval form for %s: %s", self.name, e)
|
||||
return
|
||||
|
||||
for page_idx in range(num_pages):
|
||||
page = original.getPage(page_idx)
|
||||
|
||||
if page_idx == target_page:
|
||||
page_w = float(page.mediaBox.getWidth())
|
||||
page_h = float(page.mediaBox.getHeight())
|
||||
coords = self._get_sa_signature_coordinates(page_h)
|
||||
|
||||
overlay_buf = BytesIO()
|
||||
c = rl_canvas.Canvas(overlay_buf, pagesize=(page_w, page_h))
|
||||
|
||||
client_name = self.x_fc_pod_client_name or self.x_fc_sa_client_name or self.partner_id.name or ''
|
||||
if client_name:
|
||||
c.setFont('Helvetica', 11)
|
||||
c.drawString(coords['name_x'], coords['name_y'], client_name)
|
||||
|
||||
sign_date = self.x_fc_pod_signature_date or self.x_fc_sa_client_signed_date
|
||||
if sign_date:
|
||||
date_str = sign_date.strftime('%b %d, %Y')
|
||||
c.setFont('Helvetica', 11)
|
||||
c.drawString(coords['date_x'], coords['date_y'], date_str)
|
||||
|
||||
if self.x_fc_pod_signature:
|
||||
sig_data = base64.b64decode(self.x_fc_pod_signature)
|
||||
sig_image = ImageReader(BytesIO(sig_data))
|
||||
c.drawImage(
|
||||
sig_image,
|
||||
coords['sig_x'], coords['sig_y'],
|
||||
width=coords['sig_w'], height=coords['sig_h'],
|
||||
preserveAspectRatio=True, mask='auto',
|
||||
)
|
||||
|
||||
c.save()
|
||||
overlay_buf.seek(0)
|
||||
overlay_pdf = PdfFileReader(overlay_buf)
|
||||
page.mergePage(overlay_pdf.getPage(0))
|
||||
|
||||
output.addPage(page)
|
||||
|
||||
result_buf = BytesIO()
|
||||
output.write(result_buf)
|
||||
signed_pdf = result_buf.getvalue()
|
||||
|
||||
filename = f'SA_Approval_Signed_{self.name}.pdf'
|
||||
self.with_context(skip_pod_signature_hook=True).write({
|
||||
'x_fc_sa_signed_form': base64.b64encode(signed_pdf),
|
||||
@@ -1725,7 +1656,7 @@ class SaleOrder(models.Model):
|
||||
'mimetype': 'application/pdf',
|
||||
})
|
||||
self.message_post(
|
||||
body="POD signature applied to ODSP approval form (page %s)." % self.x_fc_sa_signature_page,
|
||||
body="POD signature applied to ODSP approval form (page %s)." % sig_page,
|
||||
message_type='comment',
|
||||
attachment_ids=[att.id],
|
||||
)
|
||||
@@ -6546,7 +6477,7 @@ class SaleOrder(models.Model):
|
||||
'default_model': 'sale.order',
|
||||
'default_res_ids': self.ids,
|
||||
'default_template_id': template.id,
|
||||
'default_email_layout_xmlid': 'mail.mail_notification_layout_with_responsible_signature',
|
||||
'default_email_layout_xmlid': 'mail.mail_notification_layout',
|
||||
'default_composition_mode': 'comment',
|
||||
'mark_so_as_sent': True,
|
||||
'force_email': True,
|
||||
|
||||
Reference in New Issue
Block a user