feat: format Delhivery carrier packing slip PDF into exact 4x6 thermal dimensions
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 36s

This commit is contained in:
vickytechkey 2026-10-11 15:18:41 +05:30
parent 25089a04d6
commit c587e70d79
3 changed files with 60 additions and 5 deletions

View file

@ -135,6 +135,46 @@ def resolve_city_state_from_address(address_str, pincode=""):
return city, state, clean_pin return city, state, clean_pin
def format_pdf_to_4x6(pdf_bytes: bytes) -> bytes:
"""
Format a Delhivery packing slip PDF into an exact 4x6 inch (288x432 pt) thermal page.
Delhivery returns vector labels inside an A4 (595x842 pt) canvas.
This crops out the empty canvas and maps the vector label directly to 4x6 dimensions.
"""
try:
import pymupdf
src_doc = pymupdf.open(stream=pdf_bytes, filetype="pdf")
if len(src_doc) == 0:
return pdf_bytes
src_page = src_doc[0]
# Auto-detect label border/drawings from the original page
drawings = src_page.get_drawings()
outer_rects = [d["rect"] for d in drawings if d["rect"].width > 200 and d["rect"].height > 350]
if outer_rects:
label_rect = outer_rects[0]
else:
label_rect = pymupdf.Rect(211.0, 19.0, 470.0, 469.0)
# 4x6 inches in PDF points (72 points/inch)
TARGET_WIDTH = 288.0 # 4 inches
TARGET_HEIGHT = 432.0 # 6 inches
out_doc = pymupdf.open()
new_page = out_doc.new_page(width=TARGET_WIDTH, height=TARGET_HEIGHT)
padding = 4.0
target_rect = pymupdf.Rect(padding, padding, TARGET_WIDTH - padding, TARGET_HEIGHT - padding)
new_page.show_pdf_page(target_rect, src_doc, 0, clip=label_rect)
out_bytes = out_doc.tobytes()
out_doc.close()
src_doc.close()
return out_bytes
except Exception as e:
logger.warning("Failed to format PDF to 4x6: %s", e)
return pdf_bytes
class ShippingServiceClient: class ShippingServiceClient:
""" """
Client for interacting with Tradhox Shipping Microservice (shippingservice). Client for interacting with Tradhox Shipping Microservice (shippingservice).
@ -1081,7 +1121,18 @@ class ShippingServiceClient:
pdf_pkgs = pdf_json.get('packages', []) pdf_pkgs = pdf_json.get('packages', [])
if pdf_pkgs and isinstance(pdf_pkgs[0], dict): if pdf_pkgs and isinstance(pdf_pkgs[0], dict):
pdf_url = pdf_pkgs[0].get('pdf_download_link') pdf_url = pdf_pkgs[0].get('pdf_download_link')
pdf_encoding = pdf_pkgs[0].get('pdf_encoding') raw_encoding = pdf_pkgs[0].get('pdf_encoding')
if raw_encoding:
import base64
raw_bytes = base64.b64decode(raw_encoding.strip())
formatted_4x6 = format_pdf_to_4x6(raw_bytes)
pdf_encoding = base64.b64encode(formatted_4x6).decode('utf-8')
elif pdf_url:
s3_res = requests.get(pdf_url, timeout=6)
if s3_res.status_code == 200:
import base64
formatted_4x6 = format_pdf_to_4x6(s3_res.content)
pdf_encoding = base64.b64encode(formatted_4x6).decode('utf-8')
except Exception as pdf_exc: except Exception as pdf_exc:
logger.warning("Delhivery PDF link lookup notice: %s", pdf_exc) logger.warning("Delhivery PDF link lookup notice: %s", pdf_exc)

View file

@ -1640,20 +1640,23 @@ class OrderViewSet(viewsets.ModelViewSet):
token = getattr(settings, 'DELHIVERY_API_TOKEN', 'e70dfd63665335ee6e0a1094f6d34e17a126f5a6') token = getattr(settings, 'DELHIVERY_API_TOKEN', 'e70dfd63665335ee6e0a1094f6d34e17a126f5a6')
d_url = f"https://track.delhivery.com/api/p/packing_slip?wbns={awb}&pdf=true" d_url = f"https://track.delhivery.com/api/p/packing_slip?wbns={awb}&pdf=true"
try: try:
from .shipping_client import format_pdf_to_4x6
res = requests.get(d_url, headers={"Authorization": f"Token {token}"}, timeout=8) res = requests.get(d_url, headers={"Authorization": f"Token {token}"}, timeout=8)
if res.status_code == 200: if res.status_code == 200:
pkgs = res.json().get('packages', []) pkgs = res.json().get('packages', [])
if pkgs and pkgs[0].get('pdf_encoding'): if pkgs and pkgs[0].get('pdf_encoding'):
import base64 import base64
pdf_bytes = base64.b64decode(pkgs[0]['pdf_encoding']) pdf_bytes = base64.b64decode(pkgs[0]['pdf_encoding'])
response = HttpResponse(pdf_bytes, content_type='application/pdf') pdf_4x6_bytes = format_pdf_to_4x6(pdf_bytes)
response['Content-Disposition'] = f'inline; filename="delhivery_label_{awb}.pdf"' response = HttpResponse(pdf_4x6_bytes, content_type='application/pdf')
response['Content-Disposition'] = f'inline; filename="delhivery_label_4x6_{awb}.pdf"'
return response return response
elif pkgs and pkgs[0].get('pdf_download_link'): elif pkgs and pkgs[0].get('pdf_download_link'):
s3_res = requests.get(pkgs[0]['pdf_download_link'], timeout=8) s3_res = requests.get(pkgs[0]['pdf_download_link'], timeout=8)
if s3_res.status_code == 200: if s3_res.status_code == 200:
response = HttpResponse(s3_res.content, content_type='application/pdf') pdf_4x6_bytes = format_pdf_to_4x6(s3_res.content)
response['Content-Disposition'] = f'inline; filename="delhivery_label_{awb}.pdf"' response = HttpResponse(pdf_4x6_bytes, content_type='application/pdf')
response['Content-Disposition'] = f'inline; filename="delhivery_label_4x6_{awb}.pdf"'
return response return response
except Exception as e: except Exception as e:
logger.error("Failed to fetch label PDF: %s", e) logger.error("Failed to fetch label PDF: %s", e)

View file

@ -13,3 +13,4 @@ boto3
djangorestframework-simplejwt djangorestframework-simplejwt
requests requests
pymupdf