Skip to content

feat(pos): copy invoice as image from invoice history - #401

Open
NotAbdelrahmanelsayed wants to merge 3 commits into
BrainWise-DEV:developfrom
NotAbdelrahmanelsayed:feat/copy-invoice-image-pr
Open

NotAbdelrahmanelsayed wants to merge 3 commits into
BrainWise-DEV:developfrom
NotAbdelrahmanelsayed:feat/copy-invoice-image-pr

Conversation

@NotAbdelrahmanelsayed

Copy link
Copy Markdown
Contributor

Summary

Adds a Copy as Image button next to Print / Create Return in the Invoice History dialog, so cashiers can paste a customer's receipt straight into WhatsApp/Telegram/email without printing.

How it works

  • The invoice is rendered from the same /printview page the Print button opens (profile print format + letterhead, no trigger_print) in a hidden, same-origin iframe, and the .print-format element is rasterized with html-to-image. Pending offline invoices fall back to the built-in receipt (buildReceiptDocumentHTML).
  • html-to-image renders through SVG foreignObject, so the browser does the text shaping. Arabic/RTL item names come out correctly, which html2canvas gets wrong.
  • The image is written to the clipboard as PNG, because browsers only accept image/png in ClipboardItem. The blob promise is passed directly to ClipboardItem so Safari keeps the user gesture.
  • Fallback: if the clipboard is unavailable (plain http, permission denied, unsupported browser), <invoice>.jpg is downloaded instead and an info toast says so.
  • The button shows a loading state per row, and repeat clicks are ignored while an image is being rendered.

Changes

  • POS/src/utils/invoiceImage.js (new): renderInvoiceImage() and copyInvoiceImage()
  • POS/src/utils/printInvoice.js: export DEFAULT_PRINT_FORMAT, buildReceiptDocumentHTML and resolvePrintSettings for reuse (no behaviour change)
  • POS/src/components/sale/InvoiceHistoryDialog.vue: new action button and handler
  • pos_next/translations/ar.csv: Arabic strings for the button, toasts and errors
  • POS/package.json: add html-to-image@^1.11.13

Notes for reviewers

  • Frappe's screen CSS gives .print-format an A4 min-height, a shadow and margins. These are stripped on the throwaway iframe node before capture, otherwise the image has a large blank area at the bottom.
  • html-to-image's toBlob() ignores type/quality and always returns PNG, so the util uses toCanvas() + canvas.toBlob(type) to produce a real JPEG for the download.

Testing

Tested on a live ERPNext v15 site with an Arabic-locale POS, using Playwright:

  • Button renders after Create Return (RTL layout checked)
  • Regular invoice → PNG on the clipboard, identical to the printed receipt, Arabic shaped correctly (~2s)
  • Return invoice → negative amounts rendered, no blank space
  • Clipboard permission denied → <invoice>.jpg downloaded (verified real JPEG) + info toast
  • Double click → only one render
  • Hidden iframe removed after each render
  • Pending offline (local-only) invoice → built-in receipt (code path shared with existing offline printing; not exercised live)

🤖 Generated with Claude Code

https://claude.ai/code/session_01XwETwvYEMLVxyZ79tn7czZ

Adds a "Copy as Image" button next to Print / Create Return in the
Invoice History dialog. The invoice is rendered from the same /printview
page the Print button opens (built-in receipt for offline invoices) in a
hidden iframe, rasterized with html-to-image, and written to the
clipboard as PNG. When the clipboard is unavailable (http, permission
denied) it downloads <invoice>.jpg instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XwETwvYEMLVxyZ79tn7czZ
Invoice rows from some list endpoints omit pos_profile, which made the
image fall back to the default print format instead of the profile's.
Look the profile up from the Sales Invoice when it's missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XwETwvYEMLVxyZ79tn7czZ
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had recent activity for 21 days.

To keep this PR open, please:

  • Rebase on the latest develop branch
  • Address any pending review comments
  • Reply with an update on the PR status

If no further activity occurs within the next 14 days, this PR will be automatically closed.

@github-actions github-actions Bot added the stale label Oct 18, 2026
@engahmed1190 engahmed1190 added pinned Exempt from stale bot and removed stale labels Oct 25, 2026
…e-image-pr

# Conflicts:
#	pos_next/translations/ar.csv
@NotAbdelrahmanelsayed

Copy link
Copy Markdown
Contributor Author

I merged current develop into this branch (3d7b956). The only conflict was in ar.csv, and I kept both sides. vitest run passes and vite build compiles cleanly. It's ready for review.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pinned Exempt from stale bot

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants