einvoice 0.2.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +59 -21
- data/bin/console +0 -3
- data/docs/neweb.md +347 -0
- data/einvoice.gemspec +2 -0
- data/lib/einvoice/client.rb +16 -0
- data/lib/einvoice/connection.rb +1 -1
- data/lib/einvoice/neweb/model/base.rb +1 -0
- data/lib/einvoice/neweb/model/invoice.rb +11 -1
- data/lib/einvoice/neweb/model/invoice_item.rb +4 -4
- data/lib/einvoice/neweb/model/pre_invoice.rb +1 -1
- data/lib/einvoice/neweb/model/query.rb +43 -0
- data/lib/einvoice/neweb/model/seller_invoice.rb +1 -1
- data/lib/einvoice/neweb/provider.rb +22 -1
- data/lib/einvoice/neweb/result.rb +12 -4
- data/lib/einvoice/neweb/validator/invoice_item_validator.rb +43 -0
- data/lib/einvoice/neweb/validator/invoice_validator.rb +8 -0
- data/lib/einvoice/result.rb +4 -0
- data/lib/einvoice/utils.rb +0 -10
- data/lib/einvoice/version.rb +1 -1
- metadata +33 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5e69679681ee049f816b49bfed94ba21d79ea4f
|
4
|
+
data.tar.gz: f35afbf92608c3076ef352ac849bc36a94043620
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f6f42e32120b6752c2431cdb5db4d2c7fe0dd6d8fdeff460d4ee9e8d84afbde1c1cee4935ccc58c20fb77a9d968073dc622abafb136d9df81885e8e7a83fc5a
|
7
|
+
data.tar.gz: b0952bfcc6df37d28a120620a1bbe11ddf400aa99b996e0f6b817ba9c789fdfdae04fb5366b82736a4b7198f2d18be81a8cac0d9a929b682a6889f3deb546abb
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -9,12 +9,13 @@ To support the thriving e-commerce industry and lower the business costs and bar
|
|
9
9
|
|
10
10
|
Hence, there are several e-invoice services for B2B, B2C in Taiwan as the intermediate and value-adding platform like CHT, allPay, Neweb, ..etc. They mostly provide services like below:
|
11
11
|
|
12
|
-
*
|
13
|
-
* Issue an
|
14
|
-
*
|
15
|
-
*
|
16
|
-
*
|
17
|
-
*
|
12
|
+
* Issue an new invoice
|
13
|
+
* Issue an existed invoice
|
14
|
+
* Query issued invoices
|
15
|
+
* Cancel an issued invoice
|
16
|
+
* Allowance of an invoice
|
17
|
+
* Cancel allowance of an invoice
|
18
|
+
* Manage invoice numbers
|
18
19
|
|
19
20
|
Therefore, we need a API wrapper to manage and access the APIs.
|
20
21
|
|
@@ -36,24 +37,39 @@ Or install it yourself as:
|
|
36
37
|
|
37
38
|
## Usage
|
38
39
|
|
39
|
-
|
40
|
+
### Supported E-Invoice Providers
|
40
41
|
|
41
|
-
|
42
|
+
* [Neweb Technologies Co., Ltd.(藍新科技)](https://github.com/abookyun/einvoice/blob/master/docs/neweb.md)
|
43
|
+
|
44
|
+
### Setup
|
42
45
|
|
43
46
|
```ruby
|
44
47
|
Einvoice.configure do |setup|
|
45
48
|
setup.endpoint = ENV['EINVOICE_ENDPOINT']
|
49
|
+
setup.endpoint_url = ENV['EINVOICE_ENDPOINT_URL']
|
46
50
|
setup.client_id = ENV['EINVOICE_CLIENT_ID']
|
47
51
|
setup.client_secret = ENV['EINVOICE_CLIENT_SECRET']
|
48
52
|
setup.format = "xml"
|
49
53
|
end
|
50
54
|
```
|
51
55
|
|
52
|
-
###
|
56
|
+
### Initialize a client with your provider e.g. Neweb
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
client = Einvoice::Client.new(Einvoice::Neweb::Provider.new)
|
60
|
+
```
|
61
|
+
|
62
|
+
### Issue an invoice
|
63
|
+
|
64
|
+
Assume one of your customer just make an `order` including all transaction info for your `product`. After created the order you're ready to issue this invoice.
|
65
|
+
|
66
|
+
#### Generate invoice payload
|
53
67
|
|
54
68
|
```ruby
|
55
|
-
|
56
|
-
|
69
|
+
order = Order.find(params[:id])
|
70
|
+
product = order.product
|
71
|
+
|
72
|
+
payload = {
|
57
73
|
data_number: "#{order.data_number}",
|
58
74
|
data_date: "#{order.created_at}",
|
59
75
|
seller_id: "#{order.product.seller_id}",
|
@@ -94,30 +110,52 @@ def invoice_payload(order)
|
|
94
110
|
end
|
95
111
|
```
|
96
112
|
|
97
|
-
|
113
|
+
#### Issue an invoice and handle results
|
98
114
|
|
99
115
|
```ruby
|
100
|
-
|
101
|
-
|
116
|
+
result = client.issue(payload)
|
117
|
+
|
118
|
+
if result.success?
|
119
|
+
logger.info "Issue invoice for #{order.id} is successful."
|
120
|
+
else
|
121
|
+
logger.info "Issue invoice for #{order.id} is failed with #{result.errors}."
|
122
|
+
end
|
102
123
|
```
|
103
124
|
|
104
|
-
See [
|
125
|
+
See [Einvoice::Result](https://github.com/abookyun/einvoice/blob/master/lib/einvoice/result.rb)
|
126
|
+
|
127
|
+
### Query invoices
|
105
128
|
|
106
|
-
|
129
|
+
#### Generate invoice payload
|
107
130
|
|
108
131
|
```ruby
|
109
|
-
|
110
|
-
|
132
|
+
payload = {
|
133
|
+
data_number_s: "order_number1",
|
134
|
+
data_number_e: "order_number5",
|
135
|
+
invoice_date_time_s: "201512010000",
|
136
|
+
invoice_date_time_e: "201501202359",
|
137
|
+
sync_status_update: "N"
|
138
|
+
}
|
139
|
+
```
|
140
|
+
|
141
|
+
#### Query and handle results
|
111
142
|
|
143
|
+
```ruby
|
144
|
+
result = client.query(data)
|
112
145
|
if result.success?
|
113
|
-
|
146
|
+
result.data["InvoiceMap"].each do |data|
|
147
|
+
order_id = data.data_number
|
148
|
+
invoice_number = data.invoice_number
|
149
|
+
invoice_date = data.invoice_date #YYYY/MM/DD
|
150
|
+
invoice_time = data.invoice_time #HH:MM:SS(24h)
|
151
|
+
end
|
152
|
+
|
153
|
+
logger.info "Query invoice for #{order.id} is successful."
|
114
154
|
else
|
115
155
|
logger.info "Issue invoice for #{order.id} is failed with #{result.errors}."
|
116
156
|
end
|
117
157
|
```
|
118
158
|
|
119
|
-
See [Einvoice::Result](https://github.com/abookyun/einvoice/blob/master/lib/einvoice/result.rb)
|
120
|
-
|
121
159
|
## Development
|
122
160
|
|
123
161
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/bin/console
CHANGED
data/docs/neweb.md
ADDED
@@ -0,0 +1,347 @@
|
|
1
|
+
# Neweb Technologies Co., Ltd. 藍新科技電子發票 API 說明
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
### Request
|
6
|
+
|
7
|
+
* 由商家申請後,由藍新提供正式主機與測試主機 `hostname` & `code`。
|
8
|
+
* Request URL:"#{hostname} + #{action}"
|
9
|
+
* 傳送方式:(1) 以 Form Post 方式傳送 (2) UTF-8 編碼
|
10
|
+
* 參數:
|
11
|
+
* `storecode`:商家代碼
|
12
|
+
* `xmldata`:URLEncoded XML
|
13
|
+
* `hash`:驗證碼 = MD5(urlencoded_xmldata + `code`)
|
14
|
+
* 範例(以 [httpie](https://github.com/jkbrzt/httpie) 為例):
|
15
|
+
|
16
|
+
```shell
|
17
|
+
http --form POST ${HOSTNAME}/IN_PreInvoiceS.action storecode=${STORECODE} hash="d537a4807813c36816517b2a32994a35" xmldata="<InvoiceRoot><Invoice><InvoiceItem><Description>item1</Description><Quantity>1</Quantity><UnitPrice>10.0</UnitPrice><Amount>10.0</Amount><SequenceNumber>1</SequenceNumber></InvoiceItem><InvoiceItem><Description>item2</Description><Quantity>1</Quantity><UnitPrice>10.0</UnitPrice><Amount>10.0</Amount><SequenceNumber>2</SequenceNumber><Unit></Unit><Remark></Remark></InvoiceItem><DataNumber>12345</DataNumber><DataDate>2016/01/20</DataDate><SellerId>12345678</SellerId><BuyerName>name</BuyerName><BuyerId>0000000000</BuyerId><CustomsClearanceMark>1</CustomsClearanceMark><InvoiceType>07</InvoiceType><DonateMark>0</DonateMark><CarrierType></CarrierType><CarrierId1></CarrierId1><CarrierId2></CarrierId2><PrintMark>N</PrintMark><NPOBAN></NPOBAN><RandomNumber>AAAA</RandomNumber><SalesAmount>19</SalesAmount><FreeTaxSalesAmount>0</FreeTaxSalesAmount><ZeroTaxSalesAmount>0</ZeroTaxSalesAmount><TaxType>1</TaxType><TaxRate>0.05</TaxRate><TaxAmount>1</TaxAmount><TotalAmount>20</TotalAmount><Contact><Name>name</Name><Address>Taipei City</Address><TEL>0212341234</TEL><Email></Email></Contact></Invoice></InvoiceRoot>"
|
18
|
+
```
|
19
|
+
|
20
|
+
### Response
|
21
|
+
|
22
|
+
* 回應結構(各 APIs 略有不同):
|
23
|
+
* Result
|
24
|
+
* statcode
|
25
|
+
* statdesc
|
26
|
+
* data
|
27
|
+
* 範例:
|
28
|
+
|
29
|
+
```xml
|
30
|
+
<Result>
|
31
|
+
<statcode>0000</statcode>
|
32
|
+
<statdesc></statdesc>
|
33
|
+
</Result>
|
34
|
+
```
|
35
|
+
* 一般性回應碼與訊息對照表:
|
36
|
+
|
37
|
+
statcode | statdesc
|
38
|
+
---------|---------
|
39
|
+
0000 | OK
|
40
|
+
6001 | 某 node 值不符合長度要求
|
41
|
+
6002 | 某 node 值不符合型別要求(只檢查數型態)
|
42
|
+
6003 | 某 node 值為必填,卻發生空值或是 node 不存在
|
43
|
+
7001 | Xmldata 參數為空
|
44
|
+
7002 | Hash 參數為空
|
45
|
+
7003 | StoreCode 參數為空
|
46
|
+
8001 | Hash 值不符合
|
47
|
+
9998 | xmldata 結構有誤
|
48
|
+
9999 | 系統異常
|
49
|
+
|
50
|
+
## Issue an new invoice
|
51
|
+
|
52
|
+
* Request:
|
53
|
+
* Action:`IN_PreInvoiceS.action`
|
54
|
+
* XmlData:
|
55
|
+
|
56
|
+
Tag | Name | Required | Type | Length | Description
|
57
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
58
|
+
InvoiceRoot | - | Y | - | - | -
|
59
|
+
Invoice | - | Y | - | - | -
|
60
|
+
DataNumber | 單據號碼 | Y | 英數 | 20 | (SellerId & DataNumber) 需唯一
|
61
|
+
DataDate | 單據日期 | Y | 英數 | 10 | 格式:`YYYY/MM/DD`
|
62
|
+
SellerId | 賣方統一編號 | Y | 英數 | 10 | -
|
63
|
+
BuyerName | 買方名稱 | Y | 英數 | 60 | * B2B:買方-營業人名稱。<br/>* B2C:買方-業者通知消費者之個人識別碼資料,共 4 位 ASCII 或 2 位全型中文。
|
64
|
+
BuyerId | 買方統一編號 | Y | 英數 | 10 | * B2B:買方-營業人統一編號(BAN)。<br/>* B2C:買方-填滿 10 位數 字的 "0"。
|
65
|
+
CustomsClearanceMark | 通關方式註記 | N | 數 | 1 | * '1': 非經海關出口<br/>* '2': 經海關出口(若為零稅率發票,此為必填欄位)
|
66
|
+
InvoiceType | 發票類別 | Y | 英數 | 2 | * '01': 三聯式<br/>* '02': 二聯式<br/>* '03': 二聯式收銀機<br/>* '04': 特種稅額<br/>* '05': 電子計算機<br/>* '06': 三聯式收銀機<br/>* '07': 一般稅額計算之電子發票<br/>* '08': 特種稅額計算之電子發票<br/>* 電子發票僅適用第 7 項及 第 8 項
|
67
|
+
DonateMark | 捐贈註記 | Y | 英數 | 1 | * '0':表示「非捐贈發票」<br/>* '1':表示為「捐贈發票」<br/>* 此部分資料須由消費者決定,網購業者可於網站畫面上新增欄位,讓消費者輸入資訊,範例請參考「電子發票網頁說明資訊.doc」,倘消費者於愛心碼欄位有輸入資訊,則此欄位值帶 '1',其餘皆帶 '0'。
|
68
|
+
CarrierType | 載具類別 | N | 英數 | 6 | 填入平台配發的載具類別號碼,編碼規則:AA0000,第一碼行業別(英文),第二碼載具類別(英數),後四碼載具類別(序號)若現金消費無使用載具,請免填。消費者使用手機條碼索取含買方統編發票,則不論是否已列印紙本皆為必填。手機條碼:3J0002 手機載具相關資訊請參考財政部網頁若需使用網優載具進行發票代管服務,則此欄空白,由 EIVO 系統自動帶出值
|
69
|
+
CarrierId1 | 載具顯碼id | N | 英數 | 64 | 填入載具外顯碼號碼,卡片上載列之卡片號碼資訊。若紙本電子發票已列印註記為 Y,此欄位必須為空白;若此欄位非空 白,則紙本電子發票已列印註記必須為 N。消費者使用手機條碼索取含買方統編發票,則不論是否已列印紙本皆為必填。若消費者使用手機載具索取發票,則須將消費者填寫之手機載具資訊帶入此欄,範例請參考「電子發票網頁說明資訊.doc」若需使用網優載具進行發票代管服務,則此欄空白,由本系統自動帶出值
|
70
|
+
CarrierId2 | 載具隱碼id | N | 英數 | 64 | 填入載具內碼號碼,營業人應載入讀取工具所讀取之原始資訊。若紙本電子發票已列印註記為 Y,此欄位必須為空白;若此欄位非空白,則紙本電子發票已列印註記必須為 N。消費者使用手機條碼索取含買方統編發票,則不論是否已列印紙本皆為必填。若消費者使用手機載具索取發票,則須將消費者填寫之手機載具資訊帶入此欄,範例請參考「電子發票網頁說明資訊.doc」若需使用網優載具進行發票代管服務,則此欄空白,由本系統自動帶出值
|
71
|
+
PrintMark | 紙本電子發票已列印註記 | Y | 英 | 1 | * 'Y'/'N'<br/> * PrintMark 為 Y 時載具類別號碼,載具顯碼 ID, 載具隱碼 ID 必須為空白,捐贈註記必為 N。<br/>* 消費者使用手機條碼索取含買方統編發票,則不論是否已列印紙本,其載具類別號碼、載具顯碼 ID 和載具隱碼 ID 皆為必填。
|
72
|
+
NPOBAN | 發票捐贈對象統一 | N | 英數 | 10 | 受捐贈者統一編號 BAN 捐贈愛心碼請將愛心碼資料 3-7 碼「完整」填入。愛心碼申請方式請參考財政部網頁
|
73
|
+
RandomNumber | 發票防偽隨機碼 | N | 英數 | 4 | 交易當下隨機產生 4 位數值,少於 4 位者踢退;若為虛擬通路,則限填 "AAAA"
|
74
|
+
InvoiceItem | - | - | - | - | 可重複
|
75
|
+
Description | 品名 | Y | 英數 | 256 | - | - | - |
|
76
|
+
Quantity | 數量 | Y | 數 | 17 | * 商品數量:整數 12 位,小數 4 位。<br/>* 整數部分第一位不能有零,小數為零時不顯示小數點,負號請接於整數第一位前 Ex:999999999999.9999 Ex:-2356
|
77
|
+
Unit | 單位 | 選 | 英數 | 6 | 可為空白,商品單位, 除鋼鐵業外, 一般空白
|
78
|
+
UnitPrice | 單價 | Y | 數 | 17 | 商品單價 (未稅) 原幣報價,整數 12 位,小數 4 位。整數部分第一位不能有零,小數為零時不顯示小數點,負號請接於整數第一位前 Ex:999999999999.9999 Ex:-2356
|
79
|
+
Amount | 金額 | Y | 數 | 17 | * 商品單價(未稅) * 數量:整數 12 位,小數 4 位。<br/>* 整數部分第一位不能有零,小數為零時不顯示小數點,負號請接於整數第一位前 Ex:999999999999.9999 Ex:-2356
|
80
|
+
SequenceNumber | 明細排列序號 | Y | 英數 | 3 | 系統使用,不重複發票明細項目之排列序號, 第一筆商品標示 '1', 其餘接續編號
|
81
|
+
Remark | 單一欄位備註 | N | 英數 | 40 | 可為空白,若為健康捐請於本項填寫"健康捐"
|
82
|
+
SalesAmount | 應稅銷售額合計(新台幣) | Y | 數 | 12 | 整張發票應稅品銷售額合計 (未稅) 整數(小數點以下四捨五入),請注意銷售額合計不應為負數。
|
83
|
+
FreeTaxSalesAmount | 免稅銷售額合計(新台幣) | Y | 數 | 12 | 整張發票免稅品銷售額合計整數(小數點以下四捨五入),若無需求則填 0,請注意銷售額合計不應為負數。
|
84
|
+
ZeroTaxSalesAmount | 零稅率銷售額合計(新台幣) | Y | 數 | 12 | 整張發票零稅率品項銷售額合計整數(小數點以下四捨五入),若無需求則填 0,請注意銷售額合計不應為負數。
|
85
|
+
TaxType | 課稅別 | Y | 英數 | 1 | <br/>* '1':應稅<br/>* '2':零稅率<br/>* '3':免稅<br/>* '4':應稅(特種稅率)<br/>* '9':混合應稅與免稅或零稅率 (限收銀機發票無法分辨時使用)
|
86
|
+
TaxRate | 稅率 | Y | 數 | 6 | 範例: 稅率為 5% 時本欄位值為 0.05
|
87
|
+
TaxAmount | 營業稅額 | Y | 數 | 12 | 整數(小數點以下四捨五入),填寫方式參閱註 1,請注意此項稅額不應為負數
|
88
|
+
TotalAmount | 總計 | Y | 數 | 12 | 整數 (應稅銷售額合計 + 免稅銷售額合計 + 零稅率銷售額合計 + 營業稅額 = 此總計欄位),整數部分第一位不能有零,請注意此項總額不應為負數
|
89
|
+
Contact | 郵件聯絡人資訊 | - | - | - | -
|
90
|
+
Name | 姓名 | Y | 英數 | 64 | 郵寄信封上收件人
|
91
|
+
Address | 地址 | Y | 英數 | 128 | 郵寄信封上收件人地址
|
92
|
+
TEL | 電話 | N | 英數 | 64 | 聯絡人電話,若啟動簡訊通知服務則為收取簡訊電話,則此欄位必填
|
93
|
+
Email | email | N | 英數 | 512 | 聯絡人 Email,若啟動 Email 通知服務則此欄位必填,若須設定多筆 Email 則 以;符號間隔,例: aa@aa.net;bb@bb.net
|
94
|
+
CustomerDefined | 針對有印花稅需求者 | - | - | - | -
|
95
|
+
ProjectNo | 專案編號 | N | 英數 | 64 | -
|
96
|
+
PurchaseNo | 採購案號 | N | 英數 | 64 | -
|
97
|
+
StampDutyFlag | 顯示印花稅圖章 | N | 數 | 1 | 0:不需要 1:需要
|
98
|
+
|
99
|
+
註一、營業稅額欄位之填寫方式,應依照加值型及非加值型營業稅法第三十二條規定:「營業人依第十四條規定計算之銷項稅額,買受人為營業人者,應與銷售額於統一發票上分別載明之;買受人為非營業人者,應與銷售額合計開立統一發票。」填寫。上傳整合服務平台的發票內容應與開立內容一致。
|
100
|
+
|
101
|
+
* Response:
|
102
|
+
* 回應結構與訊息對照表:
|
103
|
+
|
104
|
+
Tag | Name | Required | Type | Length | Description
|
105
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
106
|
+
Result | - | Y | - | - | -
|
107
|
+
statcode | 錯誤代碼 | Y | - | - | -
|
108
|
+
statdesc | 錯誤描述 | Y | - | - | -
|
109
|
+
|
110
|
+
----
|
111
|
+
|
112
|
+
statcode | statdesc | description
|
113
|
+
:-------:|:---------|:-----------
|
114
|
+
7001 | SellerId 不符 | StoreCode 取得商店統一編號與 <SellerId/>是否相同或該 <SellerId/> 必須存在於該商家的分支統編中
|
115
|
+
7002 | 單據號碼重複 | 以 <SellerId/> And <DataNumber/> 為條件確認資料庫資料不可有重複。
|
116
|
+
7003 | B2C 模式 BuyerName 不符合 | 若 <BuyerId/> 值等於 10 位的 '0',則 <BuyerName/> 必須符合共 4 位 ASCII 或 2 位全型中文。
|
117
|
+
7004 | CustomsClearanceMark 資料不符 | <CustomsClearanceMark/>若有填寫,必須為 1 或 2
|
118
|
+
7005 | InvoiceType 資料不符 | <InvoiceType/>值必須為「01、02、03、04、05、06」其中一個
|
119
|
+
7006 | DonateMark 資料不符 | <DonateMark/>必須為 0 或 1
|
120
|
+
7007 | 捐贈發票 NPOBAN 資料不可為空 | <DonateMark/> 當值等於 '1' 時,則 <NPOBAN/> 不可為空值
|
121
|
+
7008 | PrintMark 為紙本電子發票已列印時, CarrierId1, CarrierId2, DonateMark 不符合要求 | <PrintMark/> 值=Y,則<CarrierId1/>載具顯碼 ID, <CarrierId2/> 載具隱碼 ID 必須為空白, <DonateMark/>捐贈註記必為 N
|
122
|
+
7009 | RandomNumber 資料長度不符 | <RandomNumber/> 若非為空值時,則長度不可小於四位。
|
123
|
+
7010 | SequenceNumber 不可重複 | <SequenceNumber/> 不可重複
|
124
|
+
7011 | SalesAmount 為負值 | <SalesAmount/> 不可為負數
|
125
|
+
7012 | FreeTaxSalesAmount 為負值 | <FreeTaxSalesAmount/> 不可為負數
|
126
|
+
7013 | ZeroTaxSalesAmount 為負值 | <ZeroTaxSalesAmount/> 不可為負數
|
127
|
+
7014 | TaxType 資料不符 | <TaxType/> 值限為「1、2、3、4、9」其中一項
|
128
|
+
7015 | TaxAmount 為負值 | <TaxAmount/> 不可為負數
|
129
|
+
7016 | TotalAmount 為負值 | <TotalAmount/> 不可為負數
|
130
|
+
|
131
|
+
## Issue an existed invoice
|
132
|
+
|
133
|
+
* Request:
|
134
|
+
* Action:`IN_SellerInvoiceS.action`
|
135
|
+
* XmlData:
|
136
|
+
|
137
|
+
Tag | Description | Required | Type | Length | Detail
|
138
|
+
----|-------------|----------|------|--------|-------
|
139
|
+
InvoiceRoot | - | Y | - | - | -
|
140
|
+
Invoice | - | Y | - | - | -
|
141
|
+
InvoiceNumber | 發票號碼 | Y | 英數 | 10 | (SellerId & DataNumber) 需唯一
|
142
|
+
InvoiceDate | 發票日期 | Y | 英數 | 8 | `YYYY/MM/DD` 西元年月日,平台僅接收 2006/12/06 後的所有發票
|
143
|
+
InvoiceTime | 發票時間 | Y | 英數 | 8 | HH:MM:SS(24hr);[00-23]:[0 0-59]:[00-59] 範例:23:59:59
|
144
|
+
SellerId | 賣方統一編號 | Y | 英數 | 10 | -
|
145
|
+
BuyerName | 買方名稱 | Y | 英數 | 60 | * B2B:買方-營業人名稱。<br/>* B2C:買方-業者通知消費者之個人識別碼資料,共 4 位 ASCII 或 2 位全型中文。
|
146
|
+
BuyerId | 買方統一編號 | Y | 英數 | 10 | * B2B:買方-營業人統一編號(BAN)。<br/>* B2C:買方-填滿 10 位數 字的 "0"。
|
147
|
+
CustomsClearanceMark | 通關方式註記 | N | 數 | 1 | * '1': 非經海關出口<br/>* '2': 經海關出口(若為零稅率發票,此為必填欄位)
|
148
|
+
InvoiceType | 發票類別 | Y | 英數 | 2 | * '01': 三聯式<br/>* '02': 二聯式<br/>* '03': 二聯式收銀機<br/>* '04': 特種稅額<br/>* '05': 電子計算機<br/>* '06': 三聯式收銀機<br/>* '07': 一般稅額計算之電子發票<br/>* '08': 特種稅額計算之電子發票<br/>* 電子發票僅適用第 7 項及 第 8 項
|
149
|
+
DonateMark | 捐贈註記 | Y | 英數 | 1 | * '0':表示「非捐贈發票」<br/>* '1':表示為「捐贈發票」<br/>* 此部分資料須由消費者決定,網購業者可於網站畫面上新增欄位,讓消費者輸入資訊,範例請參考「電子發票網頁說明資訊.doc」,倘消費者於愛心碼欄位有輸入資訊,則此欄位值帶 '1',其餘皆帶 '0'。
|
150
|
+
CarrierType | 載具類別 | N | 英數 | 6 | 填入平台配發的載具類別號碼,編碼規則:AA0000,第一碼行業別(英文),第二碼載具類別(英數),後四碼載具類別(序號)若現金消費無使用載具,請免填。消費者使用手機條碼索取含買方統編發票,則不論是否已列印紙本皆為必填。手機條碼:3J0002 手機載具相關資訊請參考財政部網頁若需使用網優載具進行發票代管服務,則此欄空白,由 EIVO 系統自動帶出值
|
151
|
+
CarrierId1 | 載具顯碼id | N | 英數 | 64 | 填入載具外顯碼號碼,卡片上載列之卡片號碼資訊。若紙本電子發票已列印註記為 Y,此欄位必須為空白;若此欄位非空 白,則紙本電子發票已列印註記必須為 N。消費者使用手機條碼索取含買方統編發票,則不論是否已列印紙本皆為必填。若消費者使用手機載具索取發票,則須將消費者填寫之手機載具資訊帶入此欄,範例請參考「電子發票網頁說明資訊.doc」若需使用網優載具進行發票代管服務,則此欄空白,由本系統自動帶出值
|
152
|
+
CarrierId2 | 載具隱碼id | N | 英數 | 64 | 填入載具內碼號碼,營業人應載入讀取工具所讀取之原始資訊。若紙本電子發票已列印註記為 Y,此欄位必須為空白;若此欄位非空白,則紙本電子發票已列印註記必須為 N。消費者使用手機條碼索取含買方統編發票,則不論是否已列印紙本皆為必填。若消費者使用手機載具索取發票,則須將消費者填寫之手機載具資訊帶入此欄,範例請參考「電子發票網頁說明資訊.doc」若需使用網優載具進行發票代管服務,則此欄空白,由本系統自動帶出值
|
153
|
+
PrintMark | 紙本電子發票已列印註記 | Y | 英 | 1 | * 'Y'/'N'<br/> * PrintMark 為 Y 時載具類別號碼,載具顯碼 ID, 載具隱碼 ID 必須為空白,捐贈註記必為 N。<br/>* 消費者使用手機條碼索取含買方統編發票,則不論是否已列印紙本,其載具類別號碼、載具顯碼 ID 和載具隱碼 ID 皆為必填。
|
154
|
+
NPOBAN | 發票捐贈對象統一 | N | 英數 | 10 | 受捐贈者統一編號 BAN 捐贈愛心碼請將愛心碼資料 3-7 碼「完整」填入。愛心碼申請方式請參考財政部網頁
|
155
|
+
RandomNumber | 發票防偽隨機碼 | N | 英數 | 4 | 交易當下隨機產生 4 位數值,少於 4 位者踢退;若為虛擬通路,則限填 "AAAA"
|
156
|
+
InvoiceItem | - | - | - | - | 可重複
|
157
|
+
Description | 品名 | Y | 英數 | 256 | - | - | - |
|
158
|
+
Quantity | 數量 | Y | 數 | 17 | * 商品數量:整數 12 位,小數 4 位。<br/>* 整數部分第一位不能有零,小數為零時不顯示小數點,負號請接於整數第一位前 Ex:999999999999.9999 Ex:-2356
|
159
|
+
Unit | 單位 | 選 | 英數 | 6 | 可為空白,商品單位, 除鋼鐵業外, 一般空白
|
160
|
+
UnitPrice | 單價 | Y | 數 | 17 | 商品單價 (未稅) 原幣報價,整數 12 位,小數 4 位。整數部分第一位不能有零,小數為零時不顯示小數點,負號請接於整數第一位前 Ex:999999999999.9999 Ex:-2356
|
161
|
+
Amount | 金額 | Y | 數 | 17 | * 商品單價(未稅) * 數量:整數 12 位,小數 4 位。<br/>* 整數部分第一位不能有零,小數為零時不顯示小數點,負號請接於整數第一位前 Ex:999999999999.9999 Ex:-2356
|
162
|
+
SequenceNumber | 明細排列序號 | Y | 英數 | 3 | 系統使用,不重複發票明細項目之排列序號, 第一筆商品標示 '1', 其餘接續編號
|
163
|
+
Remark | 單一欄位備註 | N | 英數 | 40 | 可為空白,若為健康捐請於本項填寫"健康捐"
|
164
|
+
SalesAmount | 應稅銷售額合計(新台幣) | Y | 數 | 12 | 整張發票應稅品銷售額合計 (未稅) 整數(小數點以下四捨五入),請注意銷售額合計不應為負數。
|
165
|
+
FreeTaxSalesAmount | 免稅銷售額合計(新台幣) | Y | 數 | 12 | 整張發票免稅品銷售額合計整數(小數點以下四捨五入),若無需求則填 0,請注意銷售額合計不應為負數。
|
166
|
+
ZeroTaxSalesAmount | 零稅率銷售額合計(新台幣) | Y | 數 | 12 | 整張發票零稅率品項銷售額合計整數(小數點以下四捨五入),若無需求則填 0,請注意銷售額合計不應為負數。
|
167
|
+
TaxType | 課稅別 | Y | 英數 | 1 | <br/>* '1':應稅<br/>* '2':零稅率<br/>* '3':免稅<br/>* '4':應稅(特種稅率)<br/>* '9':混合應稅與免稅或零稅率 (限收銀機發票無法分辨時使用)
|
168
|
+
TaxRate | 稅率 | Y | 數 | 6 | 範例: 稅率為 5% 時本欄位值為 0.05
|
169
|
+
TaxAmount | 營業稅額 | Y | 數 | 12 | 整數(小數點以下四捨五入),填寫方式參閱註 1,請注意此項稅額不應為負數
|
170
|
+
TotalAmount | 總計 | Y | 數 | 12 | 整數 (應稅銷售額合計 + 免稅銷售額合計 + 零稅率銷售額合計 + 營業稅額 = 此總計欄位),整數部分第一位不能有零,請注意此項總額不應為負數
|
171
|
+
Contact | 郵件聯絡人資訊 | - | - | - | -
|
172
|
+
Name | 姓名 | Y | 英數 | 64 | 郵寄信封上收件人
|
173
|
+
Address | 地址 | Y | 英數 | 128 | 郵寄信封上收件人地址
|
174
|
+
TEL | 電話 | N | 英數 | 64 | 聯絡人電話,若啟動簡訊通知服務則為收取簡訊電話,則此欄位必填
|
175
|
+
Email | email | N | 英數 | 512 | 聯絡人 Email,若啟動 Email 通知服務則此欄位必填,若須設定多筆 Email 則 以;符號間隔,例: aa@aa.net;bb@bb.net
|
176
|
+
CustomerDefined | 針對有印花稅需求者 | - | - | - | -
|
177
|
+
ProjectNo | 專案編號 | N | 英數 | 64 | -
|
178
|
+
PurchaseNo | 採購案號 | N | 英數 | 64 | -
|
179
|
+
StampDutyFlag | 顯示印花稅圖章 | N | 數 | 1 | 0:不需要 1:需要
|
180
|
+
|
181
|
+
註一、營業稅額欄位之填寫方式,應依照加值型及非加值型營業稅法第三十二條規定:「營業人依第十四條規定計算之銷項稅額,買受人為營業人者,應與銷售額於統一發票上分別載明之;買受人為非營業人者,應與銷售額合計開立統一發票。」填寫。上傳整合服務平台的發票內容應與開立內容一致。
|
182
|
+
|
183
|
+
* Response:
|
184
|
+
* 回應結構與訊息對照表:
|
185
|
+
|
186
|
+
Tag | Name | Required | Type | Length | Description
|
187
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
188
|
+
Result | - | Y | - | - | -
|
189
|
+
statcode | 錯誤代碼 | Y | - | - | -
|
190
|
+
statdesc | 錯誤描述 | Y | - | - | -
|
191
|
+
|
192
|
+
----
|
193
|
+
|
194
|
+
statcode | statdesc | description
|
195
|
+
:-------:|:---------|:-----------
|
196
|
+
7001 | SellerId 不符 | StoreCode 取得商店統一編號與 <SellerId/>是否相同或該 <SellerId/> 必須存在於該商家的分支統編中
|
197
|
+
7002 | 發票號碼重複 | 以 <InvoiceNumber/> 為條件確認資料庫資料不可有重複。
|
198
|
+
7003 | B2C 模式 BuyerName 不符合 | 若 <BuyerId/> 值等於 10 位的 '0',則 <BuyerName/> 必須符合共 4 位 ASCII 或 2 位全型中文。
|
199
|
+
7004 | CustomsClearanceMark 資料不符 | <CustomsClearanceMark/>若有填寫,必須為 1 或 2
|
200
|
+
7005 | InvoiceType 資料不符 | <InvoiceType/>值必須為「01、02、03、04、05、06」其中一個
|
201
|
+
7006 | DonateMark 資料不符 | <DonateMark/>必須為 0 或 1
|
202
|
+
7007 | 捐贈發票 NPOBAN 資料不可為空 | <DonateMark/> 當值等於 '1' 時,則 <NPOBAN/> 不可為空值
|
203
|
+
7008 | PrintMark 為紙本電子發票已列印時, CarrierId1, CarrierId2, DonateMark 不符合要求 | <PrintMark/> 值=Y,則<CarrierId1/>載具顯碼 ID, <CarrierId2/> 載具隱碼 ID 必須為空白, <DonateMark/>捐贈註記必為 N
|
204
|
+
7009 | RandomNumber 資料長度不符 | <RandomNumber/> 若非為空值時,則長度不可小於四位。
|
205
|
+
7010 | SequenceNumber 不可重複 | <SequenceNumber/> 不可重複
|
206
|
+
7011 | SalesAmount 為負值 | <SalesAmount/> 不可為負數
|
207
|
+
7012 | FreeTaxSalesAmount 為負值 | <FreeTaxSalesAmount/> 不可為負數
|
208
|
+
7013 | ZeroTaxSalesAmount 為負值 | <ZeroTaxSalesAmount/> 不可為負數
|
209
|
+
7014 | TaxType 資料不符 | <TaxType/> 值限為「1、2、3、4、9」其中一項
|
210
|
+
7015 | TaxAmount 為負值 | <TaxAmount/> 不可為負數
|
211
|
+
7016 | TotalAmount 為負值 | <TotalAmount/> 不可為負數
|
212
|
+
|
213
|
+
## Query issued invoices
|
214
|
+
|
215
|
+
* Request:
|
216
|
+
* Action:`IN_InvoiceMapS.action`
|
217
|
+
* XmlData:
|
218
|
+
|
219
|
+
Tag | Name | Required | Type | Length | Description
|
220
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
221
|
+
QryEvent | - | Y | - | - | -
|
222
|
+
InvoiceDateTimeS | 發票日期時間 (查詢開始) | N | 數 | 14 | yyyyMMddHHmmss
|
223
|
+
InvoiceDateTimdE | 發票日期時間 (結束) | N | 數 | 14 | yyyyMMddHHmmss
|
224
|
+
DataNumberS | 單據號碼 (查詢開始) | N | 英數 | 20 | -
|
225
|
+
DataNumberE | 單據號碼 (結束) | N | 英數 | 20 | -
|
226
|
+
SyncStatusUpdate | 是否更新同步狀態 | N | 英 | 1 | 'Y' or 'N'(default)
|
227
|
+
|
228
|
+
註:若不放條件,請將 Node 的值為空,不可省略節點。
|
229
|
+
|
230
|
+
* Response:
|
231
|
+
* 回應結構與訊息對照表:
|
232
|
+
|
233
|
+
Tag | Name | Required | Type | Length | Description
|
234
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
235
|
+
Result | - | Y | - | - | -
|
236
|
+
statcode | 錯誤代碼 | Y | - | - | -
|
237
|
+
statdesc | 錯誤描述 | Y | - | - | -
|
238
|
+
data | 資料區塊 | N | - | - | 狀態碼=0000 時,才有此 Node
|
239
|
+
InvoiceMapRoot | - | Y | - | - | -
|
240
|
+
InvoiceMap | 逐筆發票對應資料集合 | Y | - | - | 若有多筆發票對應資料,此 TAG 可重複
|
241
|
+
DataNumber | 單據號碼 | Y | 英數 | 20 | 為未配號發票檔中單據號碼
|
242
|
+
InvoiceNumber | 發票號碼 | Y | 英數 | 10 | 客戶須於本系統維護發票號碼後,本系統方可配號,並回傳此一值給營業人
|
243
|
+
InvoiceDate | 發票日期 | Y | 英數 | 10 | `YYYY/MM/DD` 西元年月日
|
244
|
+
InvoiceTime | 發票時間 | Y | 英數 | 8 | HH:MM:SS(24hr);[00-23]:[00-59]:[0 0-59] 範例:23:59:59
|
245
|
+
|
246
|
+
## Cancel an issued invoice
|
247
|
+
|
248
|
+
* Request:
|
249
|
+
* Action:`IN_CancelInvoiceS.action`
|
250
|
+
* XmlData:
|
251
|
+
|
252
|
+
Tag | Name | Required | Type | Length | Description
|
253
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
254
|
+
CancelInvoiceRoot | - | Y | - | - | -
|
255
|
+
CancelInvoice | 逐筆作廢發票資料集合 | Y | - | - | -
|
256
|
+
InvoiceDate | 發票日期 | Y | 英數 | 10 | `YYYY/MM/DD` 西元年月日,發票當初開立之日期
|
257
|
+
SellerId | 賣方識別碼 | Y | 英數 | 10 | 賣方營業人統一編號
|
258
|
+
CancelDate | 作廢日期 | Y | 英數 | 10 | `YYYY/MM/DD` 西元年月日
|
259
|
+
CancelTime | 作費時間 | Y | 英數 | 8 | HH:MM:SS; (24hr);[00-23]:[00-59]:[00 -59] 範例:23:59:59
|
260
|
+
CancelReason | 作費原因 | Y | 英數 | 20 | 長度至少為 1
|
261
|
+
ReturnTaxDocumentNumber | 專案作費核准文號 | N | 英數 | 60 | 若發票的作廢時間超過申報期間,則此欄位為必填欄位。若不填寫由上傳營業人自行負責。一般營業人二個月申報一次營業稅,則申報期為單月 15 號,超過申報期限則須與轄區國稅局申請專案核准文號方可作廢此張發票
|
262
|
+
Remark | 備註 | Y | 英數 | 200 | -
|
263
|
+
|
264
|
+
* Response:
|
265
|
+
* 回應結構與訊息對照表:
|
266
|
+
|
267
|
+
Tag | Name | Required | Type | Length | Description
|
268
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
269
|
+
Result | - | Y | - | - | -
|
270
|
+
statcode | 錯誤代碼 | Y | - | - | -
|
271
|
+
statdesc | 錯誤描述 | Y | - | - | -
|
272
|
+
|
273
|
+
----
|
274
|
+
|
275
|
+
statcode | statdesc | description
|
276
|
+
:-------:|:---------|:-----------
|
277
|
+
7001 | SellerId 不符 | StoreCode 取得商店統一編號與 <SellerId/> 是否相同且該 <SellerId/> 必須存在於該商家的分支統編中
|
278
|
+
7002 | CancelReason 資料長度最少一位 | <CancelReason/> 資料長度最少一位
|
279
|
+
|
280
|
+
## Allowance of an invoice
|
281
|
+
|
282
|
+
* Request:
|
283
|
+
* Action:`IN_AllowanceS.action`
|
284
|
+
* XmlData:
|
285
|
+
|
286
|
+
Tag | Name | Required | Type | Length | Description
|
287
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
288
|
+
|
289
|
+
* Response:
|
290
|
+
* 回應結構與訊息對照表:
|
291
|
+
|
292
|
+
Tag | Name | Required | Type | Length | Description
|
293
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
294
|
+
Result | - | Y | - | - | -
|
295
|
+
statcode | 錯誤代碼 | Y | - | - | -
|
296
|
+
statdesc | 錯誤描述 | Y | - | - | -
|
297
|
+
|
298
|
+
----
|
299
|
+
|
300
|
+
statcode | statdesc | description
|
301
|
+
:-------:|:---------|:-----------
|
302
|
+
|
303
|
+
## Cancel allowance of an invoice
|
304
|
+
|
305
|
+
* Request:
|
306
|
+
* Action:`IN_CancelAllowanceS.action`
|
307
|
+
* XmlData:
|
308
|
+
|
309
|
+
Tag | Name | Required | Type | Length | Description
|
310
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
311
|
+
|
312
|
+
* Response:
|
313
|
+
* 回應結構與訊息對照表:
|
314
|
+
|
315
|
+
Tag | Name | Required | Type | Length | Description
|
316
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
317
|
+
Result | - | Y | - | - | -
|
318
|
+
statcode | 錯誤代碼 | Y | - | - | -
|
319
|
+
statdesc | 錯誤描述 | Y | - | - | -
|
320
|
+
|
321
|
+
----
|
322
|
+
|
323
|
+
statcode | statdesc | description
|
324
|
+
:-------:|:---------|:-----------
|
325
|
+
|
326
|
+
## Assign invoice number for branches
|
327
|
+
|
328
|
+
* Request:
|
329
|
+
* Action:`IN_BranchTrackS.action`
|
330
|
+
* XmlData:
|
331
|
+
|
332
|
+
Tag | Name | Required | Type | Length | Description
|
333
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
334
|
+
|
335
|
+
* Response:
|
336
|
+
* 回應結構與訊息對照表:
|
337
|
+
|
338
|
+
Tag | Name | Required | Type | Length | Description
|
339
|
+
:---|:-----|:--------:|:----:|:------:|:-----------
|
340
|
+
Result | - | Y | - | - | -
|
341
|
+
statcode | 錯誤代碼 | Y | - | - | -
|
342
|
+
statdesc | 錯誤描述 | Y | - | - | -
|
343
|
+
|
344
|
+
----
|
345
|
+
|
346
|
+
statcode | statdesc | description
|
347
|
+
:-------:|:---------|:-----------
|
data/einvoice.gemspec
CHANGED
@@ -32,4 +32,6 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_development_dependency "rspec"
|
33
33
|
spec.add_development_dependency "factory_girl"
|
34
34
|
spec.add_development_dependency "shoulda-matchers"
|
35
|
+
spec.add_development_dependency "vcr"
|
36
|
+
spec.add_development_dependency "webmock"
|
35
37
|
end
|
data/lib/einvoice/client.rb
CHANGED
@@ -9,5 +9,21 @@ module Einvoice
|
|
9
9
|
def issue(payload, options = {})
|
10
10
|
provider.issue(payload, options)
|
11
11
|
end
|
12
|
+
|
13
|
+
def query(payload, options = {})
|
14
|
+
provider.query(payload, options = {})
|
15
|
+
end
|
16
|
+
|
17
|
+
def cancel(payload, options = {})
|
18
|
+
provider.cancel(payload, options = {})
|
19
|
+
end
|
20
|
+
|
21
|
+
def allowance_for(payload, options = {})
|
22
|
+
provider.allowance_for(payload, options = {})
|
23
|
+
end
|
24
|
+
|
25
|
+
def cancel_allowance(payload, options = {})
|
26
|
+
provider.cancel_allowance(payload, options = {})
|
27
|
+
end
|
12
28
|
end
|
13
29
|
end
|
data/lib/einvoice/connection.rb
CHANGED
@@ -12,7 +12,7 @@ module Einvoice
|
|
12
12
|
}
|
13
13
|
|
14
14
|
::Faraday::Connection.new(options) do |connection|
|
15
|
-
connection.request :digest_neweb, client_secret
|
15
|
+
connection.request :digest_neweb, client_secret if self.class == Einvoice::Neweb::Provider
|
16
16
|
connection.request :url_encoded
|
17
17
|
|
18
18
|
# Parser
|
@@ -48,12 +48,22 @@ module Einvoice
|
|
48
48
|
validates :tax_type, presence: true, length: { is: 1 }, inclusion: { in: %w(1 2 3 4 9) }
|
49
49
|
validates :tax_rate, presence: true, length: { maximum: 6 }
|
50
50
|
validates :tax_amount, presence: true, length: { maximum: 12 }, numericality: { greater_than_or_equal_to: 0 }
|
51
|
-
validates :total_amount, presence: true, length: { maximum: 12 }, numericality: { greater_than_or_equal_to: 0 }
|
51
|
+
validates :total_amount, presence: true, length: { maximum: 12 }, numericality: { greater_than_or_equal_to: 0 }, total_amount: true
|
52
52
|
validates :contact, presence: true
|
53
53
|
|
54
54
|
def initialize
|
55
55
|
raise NotImplementedError, "You should initialize with subclasses"
|
56
56
|
end
|
57
|
+
|
58
|
+
def payload
|
59
|
+
serializable_hash(except: [:errors, :validation_context], include: [:invoice_item, :contact, :customer_defined])
|
60
|
+
end
|
61
|
+
|
62
|
+
def wrapped_payload
|
63
|
+
{ invoice_root:
|
64
|
+
{ invoice: payload }
|
65
|
+
}
|
66
|
+
end
|
57
67
|
end
|
58
68
|
end
|
59
69
|
end
|
@@ -15,11 +15,11 @@ module Einvoice
|
|
15
15
|
attr_accessor *VALID_OPTIONS_KEYS
|
16
16
|
|
17
17
|
validates :description, presence: true, length: { maximum: 256 }
|
18
|
-
validates :quantity, presence: true, length: { maximum: 17 }
|
18
|
+
validates :quantity, presence: true, length: { maximum: 17 }, quantity: true
|
19
19
|
validates :unit, length: { maximum: 6 }
|
20
|
-
validates :unit_price, presence: true, length: { maximum: 17 }
|
21
|
-
validates :amount, presence: true, length: { maximum: 17 }
|
22
|
-
validates :sequence_number, presence: true, length: { maximum: 3 }
|
20
|
+
validates :unit_price, presence: true, length: { maximum: 17 }, unit_price: true
|
21
|
+
validates :amount, presence: true, length: { maximum: 17 }, amount: true
|
22
|
+
validates :sequence_number, presence: true, length: { maximum: 3 }, format: { with: /\A[1-9]|[1-9][0-9]|[1-9][0-9][0-9]\Z/ }
|
23
23
|
validates :remark, length: { maximum: 40 }
|
24
24
|
end
|
25
25
|
end
|
@@ -7,7 +7,7 @@ module Einvoice
|
|
7
7
|
attr_accessor *TYPE_SPECIFIC_KEYS
|
8
8
|
|
9
9
|
validates :data_number, presence: true, length: { maximum: 20 }
|
10
|
-
validates :data_date, presence: true, length: { maximum: 10 }, format: { with: /\A\d{4}\/\d{2}\/\d{2}\
|
10
|
+
validates :data_date, presence: true, length: { maximum: 10 }, format: { with: /\A\d{4}\/\d{2}\/\d{2}\Z/ }
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
# overwritten
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Einvoice
|
2
|
+
module Neweb
|
3
|
+
module Model
|
4
|
+
class Query < Base
|
5
|
+
VALID_OPTIONS_KEYS = [
|
6
|
+
:invoice_date_time_s,
|
7
|
+
:invoice_date_time_e,
|
8
|
+
:data_number_s,
|
9
|
+
:data_number_e,
|
10
|
+
:sync_status_update
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
attr_accessor *VALID_OPTIONS_KEYS
|
14
|
+
|
15
|
+
validates :invoice_date_time_s, presence: true, length: { maximum: 14 }, format: { with: /\A\d{4}\d{2}\d{2}\d{2}\d{2}\Z/ }
|
16
|
+
validates :invoice_date_time_e, presence: true, length: { maximum: 14 }, format: { with: /\A\d{4}\d{2}\d{2}\d{2}\d{2}\Z/ }
|
17
|
+
validates :data_number_s, presence: true, length: { maximum: 20 }
|
18
|
+
validates :data_number_e, presence: true, length: { maximum: 20 }
|
19
|
+
validates :sync_status_update, presence: true, length: { maximum: 1 }
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
# overwritten
|
23
|
+
end
|
24
|
+
|
25
|
+
def attributes=(hash)
|
26
|
+
hash.each do |key, value|
|
27
|
+
send("#{key}=", value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def payload
|
32
|
+
serializable_hash(except: [:errors, :validation_context])
|
33
|
+
end
|
34
|
+
|
35
|
+
def wrapped_payload
|
36
|
+
{ invoice_map_root:
|
37
|
+
{ invoice_map: payload }
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -7,7 +7,7 @@ module Einvoice
|
|
7
7
|
attr_accessor *TYPE_SPECIFIC_KEYS
|
8
8
|
|
9
9
|
validates :invoice_number, presence: true, length: { maximum: 20 }
|
10
|
-
validates :invoice_date, presence: true, length: { maximum: 10 }, format: { with: /\A\d{4}\/\d{2}\/\d{2}\
|
10
|
+
validates :invoice_date, presence: true, length: { maximum: 10 }, format: { with: /\A\d{4}\/\d{2}\/\d{2}\Z/ }
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
# overwritten
|
@@ -7,6 +7,7 @@ require "einvoice/neweb/model/invoice_item"
|
|
7
7
|
require "einvoice/neweb/model/invoice"
|
8
8
|
require "einvoice/neweb/model/pre_invoice"
|
9
9
|
require "einvoice/neweb/model/seller_invoice"
|
10
|
+
require "einvoice/neweb/model/query"
|
10
11
|
|
11
12
|
require "einvoice/neweb/result"
|
12
13
|
|
@@ -32,7 +33,7 @@ module Einvoice
|
|
32
33
|
request.url endpoint_url || endpoint + action
|
33
34
|
request.body = {
|
34
35
|
storecode: client_id,
|
35
|
-
xmldata: encode_xml(camelize(
|
36
|
+
xmldata: encode_xml(camelize(invoice.wrapped_payload))
|
36
37
|
}
|
37
38
|
end.body
|
38
39
|
|
@@ -41,6 +42,26 @@ module Einvoice
|
|
41
42
|
Einvoice::Neweb::Result.new(invoice.errors)
|
42
43
|
end
|
43
44
|
end
|
45
|
+
|
46
|
+
def query(payload, options)
|
47
|
+
action = "IN_InvoiceMapS.action"
|
48
|
+
query = Einvoice::Neweb::Model::Query.new
|
49
|
+
query.from_json(payload.to_json)
|
50
|
+
|
51
|
+
if query.valid?
|
52
|
+
response = connection.post do |request|
|
53
|
+
request.url endpoint_url || endpoint + action
|
54
|
+
request.body = {
|
55
|
+
storecode: client_id,
|
56
|
+
xmldata: encode_xml(camelize(query.wrapped_payload))
|
57
|
+
}
|
58
|
+
end.body
|
59
|
+
|
60
|
+
Einvoice::Neweb::Result.new(response)
|
61
|
+
else
|
62
|
+
Einvoice::Neweb::Result.new(query.errors)
|
63
|
+
end
|
64
|
+
end
|
44
65
|
end
|
45
66
|
end
|
46
67
|
end
|
@@ -5,7 +5,7 @@ module Einvoice
|
|
5
5
|
if response.is_a? ActiveModel::Errors
|
6
6
|
response.full_messages.join('; ')
|
7
7
|
else
|
8
|
-
data = response && (response
|
8
|
+
data = response && (response["Result"]["Invoice"] || response["Result"])
|
9
9
|
data["statcode"] == "0000" ? nil : "#{data["statcode"]}: #{data["statdesc"]}" if data
|
10
10
|
end
|
11
11
|
end
|
@@ -14,9 +14,17 @@ module Einvoice
|
|
14
14
|
if response.is_a? ActiveModel::Errors
|
15
15
|
false
|
16
16
|
else
|
17
|
-
response && response
|
18
|
-
|
19
|
-
|
17
|
+
data = response && (response["Result"]["Invoice"] || response["Result"])
|
18
|
+
data["statcode"] == "0000" if data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def data
|
23
|
+
if response.is_a? ActiveModel::Errors
|
24
|
+
nil
|
25
|
+
else
|
26
|
+
data = response && (response["Result"]["Invoice"] || response["Result"])
|
27
|
+
data["InvoiceMapRoot"] if data["statcode"] == "0000"
|
20
28
|
end
|
21
29
|
end
|
22
30
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Einvoice
|
2
|
+
module Neweb
|
3
|
+
module Validator
|
4
|
+
class QuantityValidator < ActiveModel::EachValidator
|
5
|
+
include Einvoice::Neweb::Validator
|
6
|
+
|
7
|
+
def validate_each(record, attribute, value)
|
8
|
+
unless valid_float?(value)
|
9
|
+
record.errors.add attribute, options[:message] || :invalid
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class UnitPriceValidator < ActiveModel::EachValidator
|
15
|
+
include Einvoice::Neweb::Validator
|
16
|
+
|
17
|
+
def validate_each(record, attribute, value)
|
18
|
+
unless valid_float?(value)
|
19
|
+
record.errors.add attribute, options[:message] || :invalid
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class AmountValidator < ActiveModel::EachValidator
|
25
|
+
include Einvoice::Neweb::Validator
|
26
|
+
|
27
|
+
def validate_each(record, attribute, value)
|
28
|
+
unless valid_float?(value)
|
29
|
+
record.errors.add attribute, options[:message] || :invalid
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid_float?(value)
|
35
|
+
integer, digit = value.to_s.split(".")[0..1]
|
36
|
+
float_value = value.to_f.to_s
|
37
|
+
|
38
|
+
return false if integer.nil? || digit.nil? || integer.delete("-").size > 12 || digit.try(:size) > 4
|
39
|
+
return false if integer != float_value.split(".")[0] || digit != float_value.split(".")[1]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -41,6 +41,14 @@ module Einvoice
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
class TotalAmountValidator < ActiveModel::EachValidator
|
46
|
+
def validate_each(record, attribute, value)
|
47
|
+
unless value != record.attributes.values_at("sales_amount", "free_tax_sales_amount", "zero_tax_sales_amount", "tax_amount").map(&:to_i).inject(&:+)
|
48
|
+
record.errors.add attribute, options[:message] || :invalid
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
44
52
|
end
|
45
53
|
end
|
46
54
|
end
|
data/lib/einvoice/result.rb
CHANGED
@@ -13,5 +13,9 @@ module Einvoice
|
|
13
13
|
def success?
|
14
14
|
raise NotImplementedError, 'You must initialize one of Einvoice::Response subclasses then use it.'
|
15
15
|
end
|
16
|
+
|
17
|
+
def data
|
18
|
+
raise NotImplementedError, 'You must initialize one of Einvoice::Response subclasses then use it.'
|
19
|
+
end
|
16
20
|
end
|
17
21
|
end
|
data/lib/einvoice/utils.rb
CHANGED
@@ -2,16 +2,6 @@ require "gyoku"
|
|
2
2
|
|
3
3
|
module Einvoice
|
4
4
|
module Utils
|
5
|
-
def serialize(object)
|
6
|
-
object.serializable_hash(except: [:errors, :validation_context], include: [:invoice_item, :contact, :customer_defined])
|
7
|
-
end
|
8
|
-
|
9
|
-
def wrap(hash)
|
10
|
-
{ invoice_root:
|
11
|
-
{ invoice: hash }
|
12
|
-
}
|
13
|
-
end
|
14
|
-
|
15
5
|
def camelize(hash)
|
16
6
|
hash.deep_transform_keys { |k| k.to_s.camelize }
|
17
7
|
end
|
data/lib/einvoice/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: einvoice
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Yun
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -178,6 +178,34 @@ dependencies:
|
|
178
178
|
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: vcr
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: webmock
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
181
209
|
description:
|
182
210
|
email:
|
183
211
|
- abookyun@gmail.com
|
@@ -194,6 +222,7 @@ files:
|
|
194
222
|
- Rakefile
|
195
223
|
- bin/console
|
196
224
|
- bin/setup
|
225
|
+
- docs/neweb.md
|
197
226
|
- einvoice.gemspec
|
198
227
|
- lib/einvoice.rb
|
199
228
|
- lib/einvoice/client.rb
|
@@ -205,9 +234,11 @@ files:
|
|
205
234
|
- lib/einvoice/neweb/model/invoice.rb
|
206
235
|
- lib/einvoice/neweb/model/invoice_item.rb
|
207
236
|
- lib/einvoice/neweb/model/pre_invoice.rb
|
237
|
+
- lib/einvoice/neweb/model/query.rb
|
208
238
|
- lib/einvoice/neweb/model/seller_invoice.rb
|
209
239
|
- lib/einvoice/neweb/provider.rb
|
210
240
|
- lib/einvoice/neweb/result.rb
|
241
|
+
- lib/einvoice/neweb/validator/invoice_item_validator.rb
|
211
242
|
- lib/einvoice/neweb/validator/invoice_validator.rb
|
212
243
|
- lib/einvoice/provider.rb
|
213
244
|
- lib/einvoice/result.rb
|