feat: format Delhivery carrier packing slip PDF into exact 4x6 thermal dimensions
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 36s
All checks were successful
Deploy Beta (NATIVE) / deploy (push) Successful in 36s
This commit is contained in:
parent
25089a04d6
commit
c587e70d79
3 changed files with 60 additions and 5 deletions
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
11
api/views.py
11
api/views.py
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@ boto3
|
||||||
djangorestframework-simplejwt
|
djangorestframework-simplejwt
|
||||||
|
|
||||||
requests
|
requests
|
||||||
|
pymupdf
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue