Credit note
Names the invoice it corrects, its original amount and the reason. Amounts are negative throughout.
The solid total panel is a rect with spans drawn over it: rect does not advance the cursor, which is what makes an overlay possible.
Overlay panel
VAT breakdown
Negative amounts
1 page
render_credit_note.rb
ruby
require 'json'
require 'soli/pdf'
template = JSON.parse(File.read('credit_note.template.json'))
data = JSON.parse(File.read('credit_note.data.json'))
pdf = Soli::PDF.render(
template: template,
data: data,
title: 'Credit note CN-2025-0031'
)
File.binwrite('credit_note.pdf', pdf)
Run it yourself
- Add the gem to your Gemfile — see Installation.
- Download credit_note.template.json and credit_note.data.json.
- Run
ruby render_credit_note.rb.
credit_note.template.json
json
{
"fonts": ["titillium"],
"options": { "header_height": 0 },
"footer": [
{ "type": "paragraph", "value": "${seller.name} · ${seller.address} · SIREN ${seller.siren} · VAT ${seller.vat_number} · Page #PAGE# of #TOTAL_PAGE#", "options": { "alignment": "center", "fontSize": 7.5, "color": "6B7280" } }
],
"content": [
{ "type": "hr", "color": "9F1239", "thickness": 3 },
{ "type": "move", "y": 16 },
{
"type": "table",
"header_columns": [
{
"content": [
{ "type": "text", "value": "${seller.name}", "fontSize": 15, "fontWeight": "bold" },
{ "type": "text", "value": "${seller.tagline}", "fontSize": 9 }
],
"width": 280, "alignment": "left",
"borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" }
},
{
"content": [
{ "type": "text", "value": "CREDIT NOTE", "fontSize": 21, "fontWeight": "bold" },
{ "type": "text", "value": "${credit.number} · ${credit.issued}", "fontSize": 9.5 }
],
"width": 201, "alignment": "right",
"borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" }
}
],
"rows": [],
"options": { "header": { "textColor": "9F1239" }, "padding_x": 0, "padding_y": 0 }
},
{ "type": "move", "y": 20 },
{ "type": "rect", "width": 481, "height": 68, "fill": "FDF2F5", "border": "F0CBD6", "borderWidth": 0.8 },
{ "type": "move", "x": 16, "y": 11 },
{ "type": "paragraph", "spans": [ { "text": "THIS CREDIT NOTE RELATES TO", "fontWeight": "bold", "color": "9F1239" } ], "options": { "fontSize": 7.5 } },
{ "type": "move", "y": 2 },
{ "type": "paragraph", "spans": [
{ "text": "Invoice ${original.number}", "fontWeight": "bold", "color": "1F2937" },
{ "text": " issued ${original.issued} · original amount ${original.amount}", "color": "5B6B82" }
], "options": { "fontSize": 10 } },
{ "type": "move", "y": 3 },
{ "type": "paragraph", "spans": [
{ "text": "Reason ", "fontWeight": "bold", "color": "9F1239" },
{ "text": "${credit.reason}", "color": "5B6B82" }
], "options": { "fontSize": 8.5 } },
{ "type": "move", "x": -16, "y": 30 },
{
"type": "table",
"header_columns": [],
"rows": [
[
{
"content": [
{ "type": "text", "value": "SUPPLIER", "fontSize": 7.5, "fontWeight": "bold" },
{ "type": "text", "value": "${seller.name}", "fontSize": 10, "fontWeight": "bold" },
{ "type": "text", "value": "${seller.city}", "fontSize": 9 },
{ "type": "text", "value": "SIREN ${seller.siren}", "fontSize": 9 },
{ "type": "text", "value": "VAT ${seller.vat_number}", "fontSize": 9 }
],
"width": 240, "alignment": "left", "valign": "top",
"borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" }
},
{
"content": [
{ "type": "text", "value": "CUSTOMER", "fontSize": 7.5, "fontWeight": "bold" },
{ "type": "text", "value": "${customer.name}", "fontSize": 10, "fontWeight": "bold" },
{ "type": "text", "value": "${customer.city}", "fontSize": 9 },
{ "type": "text", "value": "SIREN ${customer.siren}", "fontSize": 9 },
{ "type": "text", "value": "VAT ${customer.vat_number}", "fontSize": 9 }
],
"width": 241, "alignment": "left", "valign": "top",
"borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" }
}
]
],
"options": { "padding_x": 0, "padding_y": 3 }
},
{ "type": "move", "y": 20 },
{
"type": "table",
"data": "items",
"header_columns": [
{ "text": "DESCRIPTION", "width": 229, "fontSize": 8, "fontWeight": "bold", "alignment": "left", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" } },
{ "text": "QTY", "width": 40, "fontSize": 8, "fontWeight": "bold", "alignment": "center", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" } },
{ "text": "UNIT PRICE", "width": 68, "fontSize": 8, "fontWeight": "bold", "alignment": "right", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" } },
{ "text": "VAT", "width": 40, "fontSize": 8, "fontWeight": "bold", "alignment": "center", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" } },
{ "text": "NET CREDITED","width": 104, "fontSize": 8, "fontWeight": "bold", "alignment": "right", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" } }
],
"rows": [
[
{ "text": "${name}", "width": 229, "fontSize": 10, "alignment": "left", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "EFE3E7" },
{ "text": "${qty}", "width": 40, "fontSize": 10, "alignment": "center", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "EFE3E7" },
{ "text": "${unit}", "width": 68, "fontSize": 10, "alignment": "right", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "EFE3E7" },
{ "text": "${vat_rate}", "width": 40, "fontSize": 10, "alignment": "center", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "EFE3E7" },
{ "text": "${net}", "width": 104, "fontSize": 10, "alignment": "right", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "EFE3E7" }
]
],
"options": { "header": { "fillColor": "9F1239", "textColor": "FFFFFF", "borderColor": "9F1239" }, "padding_x": 6, "padding_y": 7 }
},
{ "type": "move", "y": 16 },
{
"type": "table",
"header_columns": [
{ "text": "VAT RATE", "width": 90, "fontSize": 8, "fontWeight": "bold", "alignment": "left", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "9F1239" },
{ "text": "TAXABLE BASE", "width": 110, "fontSize": 8, "fontWeight": "bold", "alignment": "right", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "9F1239" },
{ "text": "VAT CREDITED", "width": 100, "fontSize": 8, "fontWeight": "bold", "alignment": "right", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "9F1239" },
{ "text": "", "width": 181, "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "false" } }
],
"rows": [],
"options": { "padding_x": 6, "padding_y": 6 }
},
{
"type": "table",
"data": "vat_breakdown",
"header_columns": [],
"rows": [
[
{ "text": "${rate}", "width": 90, "fontSize": 10, "alignment": "left", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "EFE3E7" },
{ "text": "${base}", "width": 110, "fontSize": 10, "alignment": "right", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "EFE3E7" },
{ "text": "${amount}", "width": 100, "fontSize": 10, "alignment": "right", "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "true" }, "borderColor": "EFE3E7" },
{ "text": "", "width": 181, "borderSides": { "top": "false", "left": "false", "right": "false", "bottom": "false" } }
]
],
"options": { "padding_x": 6, "padding_y": 6 }
},
{ "type": "move", "y": 16 },
{
"type": "table",
"header_columns": [],
"rows": [
[
{ "text": "", "width": 271, "borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" } },
{ "text": "Net credited", "width": 130, "fontSize": 10, "alignment": "right", "borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" } },
{ "text": "${totals.net}", "width": 80, "fontSize": 10, "alignment": "right", "borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" } }
],
[
{ "text": "", "width": 271, "borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" } },
{ "text": "VAT credited", "width": 130, "fontSize": 10, "alignment": "right", "borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" } },
{ "text": "${totals.vat}", "width": 80, "fontSize": 10, "alignment": "right", "borderSides": { "top": "false", "bottom": "false", "left": "false", "right": "false" } }
]
],
"options": { "padding_x": 6, "padding_y": 6 }
},
{ "type": "move", "x": 271, "y": 2 },
{ "type": "rect", "width": 210, "height": 58, "fill": "9F1239" },
{ "type": "move", "x": 16, "y": 12 },
{ "type": "paragraph", "spans": [ { "text": "TOTAL CREDITED", "fontWeight": "bold", "color": "F6D3DC" } ], "options": { "fontSize": 8 } },
{ "type": "move", "y": 3 },
{ "type": "paragraph", "spans": [ { "text": "${totals.credited}", "fontWeight": "bold", "color": "FFFFFF" } ], "options": { "fontSize": 18 } },
{ "type": "move", "x": -287, "y": 26 },
{ "type": "paragraph", "value": "Settlement", "options": { "fontSize": 8, "fontWeight": "bold", "color": "9F1239" } },
{ "type": "move", "y": 3 },
{
"type": "list",
"marker": "—",
"indent": 10,
"spacing": 2,
"items": [
"${credit.settlement}",
"This credit note reduces the VAT originally declared on invoice ${original.number}. Adjust your input VAT for the period in which this note is received.",
"Retain this document with the original invoice for your statutory records."
],
"options": { "fontSize": 8, "color": "4B5A70", "lineHeight": 1.35 }
}
]
}
credit_note.data.json
json
{
"data": {
"seller": {
"name": "Meridian Instruments SAS",
"tagline": "Precision measurement and calibration",
"address": "18 rue de Paradis",
"city": "75010 Paris, France",
"vat_number": "FR75512345679",
"siren": "512 345 679"
},
"customer": {
"name": "Philharmonie Immobilier SAS",
"city": "75019 Paris, France",
"vat_number": "FR22842917361",
"siren": "842 917 361"
},
"credit": {
"number": "CN-2025-0031",
"issued": "12 Dec 2025",
"reason": "Two sensor modules returned unused within the 14-day window, plus a goodwill credit for the rescheduled calibration visit.",
"settlement": "The credited amount is refunded to the original bank account within 14 days, or offset against the next invoice if you prefer — reply to this note to choose."
},
"original": {
"number": "MI-2025-0184",
"issued": "28 Nov 2025",
"amount": "€2,430.21"
},
"items": [
{ "name": "Sensor module MX-4, returned unused", "qty": "-2", "unit": "145.00", "vat_rate": "20%", "net": "-290.00" },
{ "name": "Goodwill credit, rescheduled site visit", "qty": "-1", "unit": "120.00", "vat_rate": "20%", "net": "-120.00" }
],
"vat_breakdown": [
{ "rate": "20%", "base": "-410.00", "amount": "-82.00" }
],
"totals": {
"net": "-€410.00",
"vat": "-€82.00",
"credited": "-€492.00"
}
}
}
More in Billing