pdf50tawi

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 27, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

pdf50tawi

Go

Go library สำหรับสร้างไฟล์ PDF หนังสือรับรองการหักภาษี ณ ที่จ่าย (แบบ 50 ทวิ) พร้อมรองรับภาษาไทยเต็มรูปแบบ

Go library for generating Thai Withholding Tax certificates (แบบ 50 ทวิ) as ready-to-sign PDFs with full Thai language support.


Demo

make demo-cli

or

make demo-rest

เริ่มต้นใช้งาน / Quick start

go get github.com/AnuchitO/pdf50tawi
package main

import (
    "os"
    "github.com/AnuchitO/pdf50tawi"
)

func main() {
    // กรอกข้อมูลภาษี
    taxInfo := pdf50tawi.TaxInfo{
        Payer: pdf50tawi.Payer{
            TaxID:   "1234567890123",
            Name:    "บริษัท ตัวอย่าง จำกัด",
            Address: "123 ถนนสุขุมวิท แขวงคลองตัน เขตวัฒนา กรุงเทพฯ 10110",
        },
        Payee: pdf50tawi.Payee{
            TaxID: "3210987654321",
            Name:  "นาย ผู้รับเงิน",
            Pnd_3: true, // ระบุประเภท ภ.ง.ด. ที่ใช้
        },
        Income40_1: pdf50tawi.IncomeDetail{
            DatePaid:    "01 มกราคม 2568",
            AmountPaid:  "100,000.00",
            TaxWithheld: "3,000.00",
        },
        Totals: pdf50tawi.Totals{
            TotalAmountPaid:         "100,000.00",
            TotalTaxWithheld:        "3,000.00",
            TotalTaxWithheldInWords: "สามพันบาทถ้วน",
        },
        WithholdingType: pdf50tawi.WithholdingType{WithholdingTax: true},
        Certification: pdf50tawi.Certification{
            DateOfIssuance: pdf50tawi.DateOfIssuance{Day: "1", Month: "มกราคม", Year: "2568"},
        },
    }

    // โหลดรูปลายเซ็นและตราประทับ
    sign, _ := pdf50tawi.LoadImageFromFile("signature.png")
    seal, _ := pdf50tawi.LoadImageFromFile("logo.png")

    // สร้างไฟล์ PDF
    out, _ := os.Create("certificate.pdf")
    defer out.Close()

    pdf50tawi.IssueWHTCertificatePDF(out, taxInfo, sign, seal)
}

โหลดรูปภาพ / Loading images

library รับรูปภาพเป็น io.Reader ซึ่งมี helper function ให้เลือกใช้ตามแหล่งที่มาของรูป

The library accepts any io.Reader for the signature and seal. Use whichever helper matches your image source:

// จากไฟล์ในเครื่อง / From a local file
sign, err := pdf50tawi.LoadImageFromFile("signature.png")

// จาก multipart upload (net/http) / From a multipart upload
sign, err := pdf50tawi.LoadImageFromMultiPartFile(r, "signature")

// จาก URL สาธารณะ / From a public URL
sign, err := pdf50tawi.LoadImageFromURL("https://storage.example.com/signature.png")

// จาก URL ที่ต้องใช้ auth — สร้าง request เองด้วย standard library
// From a private/authenticated URL — build the request yourself
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
req.Header.Set("Authorization", "Bearer "+token)
sign, err := pdf50tawi.LoadImageFromRequest(req)

ถ้าไม่มีรูปลายเซ็นหรือตราประทับ ส่ง nil ได้เลย — ระบบจะข้ามช่องนั้นให้อัตโนมัติ

Pass nil for either image to omit it from the certificate.


REST API — 3 วิธีส่งรูปภาพ / 3 image strategies

server ตัวอย่าง (cmd/rest) แสดง 3 วิธีส่งรูปภาพมากับ request ให้เลือกใช้ตามความเหมาะสม ดูรายละเอียดเพิ่มเติมได้ที่ cmd/rest/README.md

The included server (cmd/rest) demonstrates three ways to supply images over HTTP — see cmd/rest/README.md for the full reference. Run the demo to see all three strategies in action:

./scripts/demo-rest.sh
วิธี / Strategy Endpoint เหมาะเมื่อ / When to use
A Multipart upload POST /api/v1/taxes/multipart client upload ไฟล์โดยตรง
B Base64 ใน JSON POST /api/v1/taxes/base64 API client ที่รับส่งแค่ JSON
C ส่ง URL มา POST /api/v1/taxes/url รูปอยู่บน CDN / S3 อยู่แล้ว

วิธี A — multipart/form-data

curl -X POST http://localhost:8080/api/v1/taxes/multipart \
  -F "taxInfo={...}" \
  -F "signature=@signature.png" \
  -F "seal=@logo.png" \
  -o certificate.pdf

วิธี B — base64 ใน JSON body

curl -X POST http://localhost:8080/api/v1/taxes/base64 \
  -H "Content-Type: application/json" \
  -d '{
    "taxInfo": {...},
    "signatureBase64": "<base64>",
    "sealBase64": "<base64>"
  }' \
  -o certificate.pdf

วิธี C — ส่ง URL ให้ server ดึงเอง

curl -X POST http://localhost:8080/api/v1/taxes/url \
  -H "Content-Type: application/json" \
  -d '{
    "taxInfo": {...},
    "signatureURL": "https://cdn.example.com/signature.png",
    "sealURL": "https://cdn.example.com/logo.png"
  }' \
  -o certificate.pdf

CLI

# รันด้วยข้อมูลตัวอย่าง / Run with demo data
./scripts/demo-cli.sh

# รันด้วยรูปของคุณเอง / Run with your own images
go run ./cmd/cli \
  --signature path/to/signature.png \
  --seal      path/to/logo.png \
  --output    certificate.pdf

ข้อกำหนดรูปภาพ / Image requirements

รูปภาพควรเป็น PNG พื้นหลังโปร่งใส และมีขนาดตามนี้เพื่อให้ตรงกับช่องในฟอร์ม

รูป / Image ขนาด / Dimensions รูปแบบ / Format
ลายเซ็น / Signature 1280 × 720 px PNG, พื้นหลังโปร่งใส
ตราประทับ / Seal (สี่เหลี่ยมจัตุรัส) 1024 × 1024 px PNG, พื้นหลังโปร่งใส
ตราประทับ / Seal (สี่เหลี่ยมผืนผ้า) 1280 × 720 px PNG, พื้นหลังโปร่งใส

รายการ field ทั้งหมด / TaxInfo reference

ดู field ทั้งหมด / Show all fields
type TaxInfo struct {
    DocumentDetails DocumentDetails // เลขที่เล่ม / เลขที่
    Payer           Payer           // ผู้จ่ายเงิน
    Payee           Payee           // ผู้มีเงินได้ — ระบุประเภท ภ.ง.ด. ด้วย bool fields

    Income40_1          IncomeDetail // 1. เงินเดือน ค่าจ้าง ตามมาตรา 40(1)
    Income40_2          IncomeDetail // 2. ค่าธรรมเนียม ค่านายหน้า ตามมาตรา 40(2)
    Income40_3          IncomeDetail // 3. ค่าแห่งลิขสิทธิ์ ตามมาตรา 40(3)
    Income40_4A         IncomeDetail // 4(ก) ดอกเบี้ย ตามมาตรา 40(4)(ก)

    // 4(ข) เงินปันผล — กรณีได้รับเครดิตภาษี
    Income40_4B_1_1      IncomeDetail // อัตราร้อยละ 30 ของกำไรสุทธิ
    Income40_4B_1_2      IncomeDetail // อัตราร้อยละ 25 ของกำไรสุทธิ
    Income40_4B_1_3      IncomeDetail // อัตราร้อยละ 20 ของกำไรสุทธิ
    Income40_4B_1_4_Rate string       // อัตราอื่น ๆ (ระบุ)
    Income40_4B_1_4      IncomeDetail

    // 4(ข) เงินปันผล — กรณีไม่ได้รับเครดิตภาษี
    Income40_4B_2_1      IncomeDetail // กำไรสุทธิที่ได้รับยกเว้น ภ.ง.ด.
    Income40_4B_2_2      IncomeDetail // เงินปันผลที่ได้รับยกเว้น
    Income40_4B_2_3      IncomeDetail // กำไรสุทธิหักผลขาดทุนยกมาไม่เกิน 5 ปี
    Income40_4B_2_4      IncomeDetail // กำไรรับรู้ทางบัญชี (equity method)
    Income40_4B_2_5_Note string       // อื่น ๆ (ระบุ)
    Income40_4B_2_5      IncomeDetail

    Income5      IncomeDetail // 5. การจ่ายเงินได้ที่ต้องหักภาษี ณ ที่จ่าย
    Income6_Note string       // 6. อื่น ๆ (ระบุ)
    Income6      IncomeDetail

    Totals          Totals          // รวมเงินได้และภาษีที่หัก
    OtherPayments   OtherPayments   // กบข. / ประกันสังคม / กองทุนสำรองเลี้ยงชีพ
    WithholdingType WithholdingType // ประเภทการหักภาษี
    Certification   Certification   // วันที่ออกหนังสือรับรอง
}

ขนาดไฟล์ผลลัพธ์ / Output size

สถานการณ์ / Scenario ขนาดไฟล์ / File size
ข้อมูลข้อความ ไม่มีรูปภาพ / Text only ~150 KB
พร้อมลายเซ็น + ตราประทับ / With signature + seal ~400–500 KB

  • bahttext — แปลงตัวเลขเป็นตัวอักษรภาษาไทย (บาท)
  • currency-formatter — จัดรูปแบบตัวเลขเงินบาท
  • date-thai-formatter — แปลงวันที่เป็นภาษาไทย (พ.ศ., ชื่อเดือนเต็ม/ย่อ)

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IssueWHTCertificatePDF

func IssueWHTCertificatePDF(outputPDF io.Writer, taxInfo TaxInfo, sign io.Reader, logo io.Reader) error

IssueWHTCertificatePDF generates a filled WHT certificate PDF.

func LoadImageFromFile

func LoadImageFromFile(file string) (io.Reader, error)

LoadImageFromFile loads a PNG or JPEG image from a local file path.

func LoadImageFromMultiPartFile

func LoadImageFromMultiPartFile(r *http.Request, field string) (io.Reader, error)

LoadImageFromMultiPartFile reads a PNG image uploaded via multipart form. field is the form field name (e.g. "signature").

func LoadImageFromRequest

func LoadImageFromRequest(req *http.Request) (io.Reader, error)

LoadImageFromRequest fetches a PNG image by executing the given HTTP request. Use this when the image URL requires custom headers such as authentication:

req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
req.Header.Set("Authorization", "Bearer "+token)
img, err := pdf50tawi.LoadImageFromRequest(req)

func LoadImageFromURL

func LoadImageFromURL(url string) (io.Reader, error)

LoadImageFromURL fetches a PNG image from the given URL.

func ValidateTaxInfo

func ValidateTaxInfo(t TaxInfo) error

ValidateTaxInfo validates all fields in TaxInfo and returns a comprehensive error if any.

Types

type Anchor

type Anchor int

Anchor represents a reference point on a PDF page for positioning text and images.

const (
	TopLeft      Anchor = iota
	TopCenter           // 1
	TopRight            // 2
	Left                // 3
	Center              // 4
	Right               // 5
	BottomLeft          // 6
	BottomCenter        // 7
	BottomRight         // 8
)

type Certification

type Certification struct {
	DateOfIssuance DateOfIssuance `json:"dateOfIssuance"`
}

type DateOfIssuance

type DateOfIssuance struct {
	Day   string `json:"day"`
	Month string `json:"month"`
	Year  string `json:"year"`
}

type DocumentDetails

type DocumentDetails struct {
	BookNumber     string `json:"bookNumber"`
	DocumentNumber string `json:"documentNumber"`
}

type ImageField

type ImageField struct {
	Reader   io.Reader
	Pos      Anchor
	Dx       float64
	Dy       float64
	Scale    float64
	Opacity  float64
	Diagonal int
	OnTop    bool
}

ImageField defines an image (signature or seal) and its position on the certificate form.

func CertificateImageFields

func CertificateImageFields(sign io.Reader, logo io.Reader) []ImageField

CertificateImageFields returns the positioned image fields for the signature and company seal.

type IncomeDetail

type IncomeDetail struct {
	DatePaid    string `json:"datePaid"`
	AmountPaid  string `json:"amountPaid"`
	TaxWithheld string `json:"taxWithheld"`
}

type OtherPayments

type OtherPayments struct {
	GovernmentPensionFund string `json:"governmentPensionFund"`
	SocialSecurityFund    string `json:"socialSecurityFund"`
	ProvidentFund         string `json:"providentFund"`
}

type Payee

type Payee struct {
	TaxID          string `json:"taxId"`
	TaxID10Digit   string `json:"taxId10Digit"`
	Name           string `json:"name"`
	Address        string `json:"address"`
	SequenceNumber string `json:"sequenceNumber"`
	Pnd_1a         bool   `json:"pnd_1a"`        // ภ.ง.ด. 1ก
	Pnd_1aSpecial  bool   `json:"pnd_1aSpecial"` // ภ.ง.ด. 1ก พิเศษ
	Pnd_2          bool   `json:"pnd_2"`         // ภ.ง.ด. 2
	Pnd_3          bool   `json:"pnd_3"`         // ภ.ง.ด. 3
	Pnd_2a         bool   `json:"pnd_2a"`        // ภ.ง.ด. 2ก
	Pnd_3a         bool   `json:"pnd_3a"`        // ภ.ง.ด. 3ก
	Pnd_53         bool   `json:"pnd_53"`        // ภ.ง.ด. 53
}

type Payer

type Payer struct {
	TaxID        string `json:"taxId"`
	TaxID10Digit string `json:"taxId10Digit"`
	Name         string `json:"name"`
	Address      string `json:"address"`
}

type TaxInfo

type TaxInfo struct {
	DocumentDetails DocumentDetails `json:"documentDetails"`
	Payer           Payer           `json:"payer"`
	Payee           Payee           `json:"payee"`

	Income40_1  IncomeDetail `json:"income40_1"`  // 1. เงินเดือน ค่าจาง เบี้ยเลี้ยง โบนัส ฯลฯ ตามมาตรา 40 (1)
	Income40_2  IncomeDetail `json:"income40_2"`  // 2. ค่าธรรมเนียม ค่านายหน้า ฯลฯ ตามมาตรา 40 (2)
	Income40_3  IncomeDetail `json:"income40_3"`  // 3. ค่าแห่งลิขสิทธิ์ ฯลฯ ตามมาตรา 40 (3)
	Income40_4A IncomeDetail `json:"income40_4A"` // 4. (ก) ดอกเบี้ย ฯลฯ ตามมาตรา 40 (4) (ก)

	// 4. (ข) เงินปันผล เงินส่วนแบ่งกำไร ฯลฯ ตามมาตรา 40 (4) (ข)
	// 4. (ข) (1) (1) กรณีผู้ได้รับเงินปันผลได้รับเครดิตภาษี โดยจ่ายจาก
	// กำไรสุทธิของกิจการที่ต้องเสียภาษีเงินได้นิติบุคคลในอัตราดังนี้
	Income40_4B_1_1      IncomeDetail `json:"income40_4B_1_1"`      // 4. (ข) (1) (1.1) อัตราร้อยละ 30 ของกำไรสุทธิ
	Income40_4B_1_2      IncomeDetail `json:"income40_4B_1_2"`      // 4. (ข) (1) (1.2) อัตราร้อยละ 25 ของกำไรสุทธิ
	Income40_4B_1_3      IncomeDetail `json:"income40_4B_1_3"`      // 4. (ข) (1) (1.3) อัตราร้อยละ 20 ของกำไรสุทธิ
	Income40_4B_1_4_Rate string       `json:"income40_4B_1_4_rate"` // 4. (ข) (1) (1.4) อัตราอื่น ๆ (ระบุ)... ของกำไรสุทธิ
	Income40_4B_1_4      IncomeDetail `json:"income40_4B_1_4"`      // 4. (ข) (1) (1.4)
	Income40_4B_2_1      IncomeDetail `json:"income40_4B_2_1"`      // 4. (ข) (2) (2.1) กำไรสุทธิของกิจการที่ได้รับยกเว้นภาษีเงินได้นิติบุคคล
	Income40_4B_2_2      IncomeDetail `json:"income40_4B_2_2"`      // 4. (ข) (2) (2.2) เงินปันผลหรือเงินส่วนแบ่งของกำไรที่ได้รับยกเว้นไม่ต้องนำมารวม คำนวณเป็นรายได้เพื่อเสียภาษีเงินได้นิติบุคคล
	Income40_4B_2_3      IncomeDetail `json:"income40_4B_2_3"`      // 4. (ข) (2) (2.3) กำไรสุทธิส่วนที่ได้หักผลขาดทุนสุทธิยกมาไม่เกิน 5 ปี ก่อนรอบระยะเวลาบัญชีปีปัจจุบัน
	Income40_4B_2_4      IncomeDetail `json:"income40_4B_2_4"`      // 4. (ข) (2) (2.4)  กำไรที่รับรู้ทางบัญชีโดยวิธีส่วนได้เสีย (equity method)
	Income40_4B_2_5_Note string       `json:"income40_4B_2_5_note"` // 4. (ข) (2) (2.5) อื่น ๆ (ระบุ)... ของกำไรสุทธิ
	Income40_4B_2_5      IncomeDetail `json:"income40_4B_2_5"`      // 4. (ข) (2) (2.5)

	Income5      IncomeDetail `json:"income5"`      // 5. การจ่ายเงินได้ที่ต้องหักภาษี ณ ที่จ่าย
	Income6      IncomeDetail `json:"income6"`      // 6. อื่น ๆ (ระบุ)
	Income6_Note string       `json:"income6_note"` // 6. อื่น ๆ (ระบุ)

	Totals          Totals          `json:"totals"`          // รวมเงิน
	OtherPayments   OtherPayments   `json:"otherPayments"`   // จ่ายภาษี
	WithholdingType WithholdingType `json:"withholdingType"` // ประเภทการหักภาษี
	Certification   Certification   `json:"certification"`   // การยืนยัน
}

type TextField

type TextField struct {
	Text     string
	Dx       float64
	Dy       float64
	FontSize int
	FontName string
	Position Anchor
}

TextField defines a text value and its position on the certificate form.

func TextFieldsFromTaxInfo

func TextFieldsFromTaxInfo(tax TaxInfo) []TextField

TextFieldsFromTaxInfo converts TaxInfo into the complete set of TextField values to be rendered on the certificate form.

type Totals

type Totals struct {
	TotalAmountPaid         string `json:"totalAmountPaid"`
	TotalTaxWithheld        string `json:"totalTaxWithheld"`
	TotalTaxWithheldInWords string `json:"totalTaxWithheldInWords"`
}

type ValidationError

type ValidationError struct {
	Errors []string
}

func (*ValidationError) Add

func (v *ValidationError) Add(msg string)

func (*ValidationError) Error

func (v *ValidationError) Error() string

func (*ValidationError) HasErrors

func (v *ValidationError) HasErrors() bool

type WithholdingType

type WithholdingType struct {
	WithholdingTax bool   `json:"withholdingTax"` // หัก ณ ที่จ่าย
	Forever        bool   `json:"forever"`        // ออกให้ตลอดไป
	OneTime        bool   `json:"oneTime"`        // ออกให้ครั้งเดียว
	Other          bool   `json:"other"`          // อื่น ๆ
	OtherDetails   string `json:"otherDetails"`   // อื่น ๆ (ระบุ)
}

Directories

Path Synopsis
cmd
cli command
rest command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL