Cetustek
Cetustek is a Ruby gem designed for handling electronic invoice operations, including invoice cancellation. It communicates with the e-invoice system through SOAP Web Services.
Features
- Electronic invoice cancellation
- XML format generation
- SOAP Web Services integration
- Environment-specific configuration (sandbox/production)
- Service-oriented architecture
- Robust error handling
Installation
Add this line to your application's Gemfile:
gem 'cetustek'
Then execute:
bundle install
Configuration
Configure Cetustek in your application:
# config/initializers/cetustek.rb
Cetustek.configure do |config|
# Set environment (:production or :sandbox)
config.environment = Rails.env.production? ? :production : :sandbox
# Set authentication credentials
config.site_id = ENV['CETUSTEK_SITE_ID']
config.username = ENV['CETUSTEK_USERNAME']
config.password = ENV['CETUSTEK_PASSWORD']
end
Usage
Issue an Invoice
invoice = YourInvoiceModel.find(invoice_id)
invoice_data = Cetustek::Models::InvoiceData.new(
order_id: invoice.order_id,
order_date: Time.zone.today,
buyer_identifier: invoice.receipt,
buyer_name: invoice.name,
buyer_email: invoice.email,
donate_mark: 0,
payment_type: 2,
items: invoice.items.map { |item|
Cetustek::Models::InvoiceItem.new(
code: item.sku,
name: item.name,
quantity: item.quantity,
unit_price: item.price
)
}
)
result = Cetustek::CreateInvoice.new(invoice_data).execute
# => { number: "GT68514542", random_number: "9654" }
Tax types (稅別)
InvoiceData defaults to taxable (TaxType 1) with a tax rate of 0.05 and a
general invoice type of 07. Use Cetustek::TaxType to switch modes:
| Constant | Code | Meaning |
|---|---|---|
TAXABLE |
1 | 應稅 |
ZERO_RATE |
2 | 零稅率(非經海關出口) |
TAX_FREE |
3 | 免稅 |
SPECIAL |
4 | 應稅(特種稅率) — set tax_rate, use invoice_type: '08' |
ZERO_RATE_CUSTOMS |
5 | 零稅率(經海關出口) |
MIXED |
9 | 混合(應稅/零稅率/免稅,限收銀機類型發票) |
Zero-rate invoice (零稅率)
Cetustek::Models::InvoiceData.new(
# ...buyer fields, items...
tax_type: Cetustek::TaxType::ZERO_RATE,
tax_rate: 0
)
Mixed-tax invoice (混稅, cash-register invoices only)
For TaxType 9 each line item must declare its own tax category via tax_type.
Accepts the symbols :taxable (default), :zero_rate, :tax_free, or the raw
DType codes ('', 'TZ', 'TN'):
Cetustek::Models::InvoiceData.new(
# ...buyer fields...
tax_type: Cetustek::TaxType::MIXED,
items: [
Cetustek::Models::InvoiceItem.new(code: 'A', name: '應稅品', quantity: 1, unit_price: 100),
Cetustek::Models::InvoiceItem.new(code: 'B', name: '零稅率品', quantity: 1, unit_price: 100, tax_type: :zero_rate),
Cetustek::Models::InvoiceItem.new(code: 'C', name: '免稅品', quantity: 1, unit_price: 100, tax_type: :tax_free)
]
)
Payment method (payment_type / PayWay)
payment_type accepts any raw code, or use Cetustek::PayWay for readability
(payment_type: Cetustek::PayWay::LINE_PAY):
| Constant | Code | Constant | Code | |
|---|---|---|---|---|
CASH |
1 | GOOGLE_PAY |
G |
|
ATM |
2 | JKO_PAY |
J |
|
CREDIT_CARD |
3 | LINE_PAY |
L |
|
CVS |
4 | PI_WALLET |
P |
|
OTHER |
5 | SAMSUNG_PAY |
S |
|
E_PAYMENT |
6 | TAIWAN_PAY |
T |
|
APPLE_PAY |
A |
EASY_WALLET |
U |
|
AFTEE |
E |
PX_PAY |
W |
|
QUAN_PAY |
X |
|||
COIN_CARD |
Z |
Donation mark (donate_mark / DonateMark)
donate_mark accepts any raw code, or use Cetustek::DonateMark:
CARRIER (0, 載具), DONATE (1, 捐贈), PAPER (2, 紙本).
Discounts and fees
The gem is a faithful wrapper of the API's invoice detail format, so it has no
built-in discount/coupon/delivery/handling concepts. Model them as ordinary line
items — use a negative unit_price for a discount:
Cetustek::Models::InvoiceItem.new(code: 'DISCOUNT', name: '折抵', quantity: 1, unit_price: -30)
Cancel an Invoice
# `invoice` responds to #number and #created_at; on success (return code "C0")
# it is updated with canceled: true.
Cetustek::CancelInvoice.new(invoice).execute
Query invoices
Cetustek::QueryInvoiceByOrderId.query(order_id) # by order id
Cetustek::QueryInvoice.query(invoice_number, invoice_year) # by invoice number + year
Cetustek::QueryInvoiceNumberByOrderId.query(order_id) # just the invoice number
Tax-inclusive vs tax-exclusive prices (hastax)
hastax comes from the order, not a fixed value: 1 (default) means the item
unit_prices already include tax; 0 means they are tax-exclusive (e.g. a tax-free
purchase). Set it on InvoiceData:
Cetustek::Models::InvoiceData.new(hastax: 0, items: [...])
Allowances (折讓單)
allowance = Cetustek::Models::AllowanceData.new(
allowance_number: 'AA20240216000001',
allowance_date: Time.zone.today,
invoice_number: 'AA10000000',
invoice_year: '2024',
tax_type: 1,
reason: '退回',
items: [
Cetustek::Models::InvoiceItem.new(code: '0001', name: '禮券', quantity: 1, unit: '本', unit_price: 800)
]
)
Cetustek::CreateAllowance.new(allowance).execute # => "A0" on success
Cetustek::CancelAllowance.new('AA20240216000001', '明細錯誤').execute # => "C0" on success
Cetustek::QueryAllowance.query('AA20240216000001')
Mobile barcode validation (手機條碼)
Cetustek::PhoneBarcode.valid?('/ABC123') # => true / false
Development
- Clone this repository
- Run
bin/setupto install dependencies - Run
bin/consolefor an interactive prompt to experiment - Run
bundle exec rspecto run the test suite
Requirements
- Ruby >= 3.0.0
oxgem for XML processingsavongem for SOAP services
Contributing
- Fork this project
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -am 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Versioning
This project follows Semantic Versioning. See the CHANGELOG.md file for version details.
License
This gem is available as open source under the terms of the MIT License.