kra-etims-sdk 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl

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.
kra_etims_sdk/schemas.py CHANGED
@@ -1,25 +1,33 @@
1
1
  from typing import List, Optional
2
2
  from typing_extensions import Annotated
3
-
4
3
  from pydantic import (
5
4
  BaseModel,
6
5
  Field,
7
6
  conint,
8
7
  condecimal,
9
8
  StringConstraints,
9
+ AfterValidator,
10
10
  )
11
+ import re
12
+
11
13
 
12
14
  # =========================================================
13
- # COMMON CONSTRAINED TYPES (Pydantic v2 style)
15
+ # COMMON CONSTRAINED TYPES (aligned with PHP)
14
16
  # =========================================================
15
17
 
16
18
  TIN = Annotated[str, StringConstraints(min_length=1, max_length=20)]
17
- BHF = Annotated[str, StringConstraints(min_length=1, max_length=20)]
19
+ BHF_ID = Annotated[str, StringConstraints(min_length=1, max_length=10)] # Fixed: was 20
20
+
21
+ YN = Annotated[str, StringConstraints(pattern=r"^[YN]$")]
22
+
23
+ # YYYYMMDDHHMMSS (exactly 14 digits)
24
+ DT14 = Annotated[str, StringConstraints(pattern=r"^\d{14}$")]
18
25
 
19
- YN = Annotated[str, StringConstraints(pattern="^[YN]$")]
26
+ # Flexible date: 8 to 14 digits (used in purchase/sales dates)
27
+ FLEX_DATE = Annotated[str, StringConstraints(min_length=8, max_length=14)]
20
28
 
21
- DT14 = Annotated[str, StringConstraints(pattern=r"^\d{14}$")] # YYYYMMDDHHmmss
22
- DT8 = Annotated[str, StringConstraints(pattern=r"^\d{8}$")] # YYYYMMDD
29
+ # Exactly 8-digit date (YYYYMMDD)
30
+ DT8 = Annotated[str, StringConstraints(pattern=r"^\d{8}$")]
23
31
 
24
32
 
25
33
  # =========================================================
@@ -28,185 +36,273 @@ DT8 = Annotated[str, StringConstraints(pattern=r"^\d{8}$")] # YYYYMMDD
28
36
 
29
37
  class Initialization(BaseModel):
30
38
  tin: TIN
31
- bhfId: BHF
32
- dvcSrlNo: Annotated[str, StringConstraints(min_length=1, max_length=50)]
39
+ bhfId: BHF_ID
40
+ dvcSrlNo: Annotated[str, StringConstraints(min_length=1)] # no max in PHP
33
41
 
34
42
 
35
43
  # =========================================================
36
- # BASIC LIST REQUESTS
44
+ # COMMON REQUESTS
37
45
  # =========================================================
38
46
 
39
- class CodeList(BaseModel):
40
- tin: TIN
41
- bhfId: BHF
47
+ class LastReqOnly(BaseModel):
42
48
  lastReqDt: DT14
43
49
 
44
50
 
45
- class BhfList(BaseModel):
46
- lastReqDt: DT14
47
-
48
-
49
- class NoticeList(BaseModel):
50
- tin: TIN
51
- bhfId: BHF
52
- lastReqDt: DT14
53
-
54
-
55
- class TaxpayerInfo(BaseModel):
56
- tin: TIN
57
- bhfId: BHF
58
- lastReqDt: DT14
59
-
60
-
61
- class CustomerList(BaseModel):
62
- tin: TIN
63
- bhfId: BHF
64
- lastReqDt: DT14
51
+ class CustSearchReq(BaseModel):
52
+ custmTin: TIN
65
53
 
66
54
 
67
55
  # =========================================================
68
56
  # BRANCH MANAGEMENT
69
57
  # =========================================================
70
58
 
71
- class BranchInsurance(BaseModel):
72
- isrccCd: str
73
- isrccNm: str
74
- isrcRt: condecimal(ge=0)
59
+ class BranchCustomer(BaseModel):
60
+ custNo: Annotated[str, StringConstraints(min_length=1)]
61
+ custTin: TIN
62
+ custNm: Annotated[str, StringConstraints(min_length=1)]
75
63
  useYn: YN
76
- regrNm: str
77
- regrId: str
64
+ regrId: Annotated[str, StringConstraints(min_length=1)]
65
+ regrNm: Annotated[str, StringConstraints(min_length=1)]
66
+ modrId: Optional[str] = None
67
+ modrNm: Optional[str] = None
78
68
 
79
69
 
80
- class BranchUserAccount(BaseModel):
81
- userId: str
82
- userNm: str
83
- pwd: str
70
+ class BranchUser(BaseModel):
71
+ userId: Annotated[str, StringConstraints(min_length=1)]
72
+ userNm: Annotated[str, StringConstraints(min_length=1)]
73
+ pwd: Annotated[str, StringConstraints(min_length=1)]
84
74
  useYn: YN
85
- regrNm: str
86
- regrId: str
75
+ regrId: Annotated[str, StringConstraints(min_length=1)]
76
+ regrNm: Annotated[str, StringConstraints(min_length=1)]
77
+ modrId: Optional[str] = None
78
+ modrNm: Optional[str] = None
87
79
 
88
80
 
89
- class CustomerInfo(BaseModel):
90
- custNo: str
91
- custTin: str
92
- custNm: str
81
+ class BranchInsurance(BaseModel):
82
+ isrccCd: Annotated[str, StringConstraints(min_length=1)]
83
+ isrccNm: Annotated[str, StringConstraints(min_length=1)]
84
+ isrcRt: condecimal(ge=0)
93
85
  useYn: YN
94
- regrNm: str
95
- regrId: str
86
+ regrId: Annotated[str, StringConstraints(min_length=1)]
87
+ regrNm: Annotated[str, StringConstraints(min_length=1)]
88
+ modrId: Optional[str] = None
89
+ modrNm: Optional[str] = None
96
90
 
97
91
 
98
92
  # =========================================================
99
- # PURCHASE
93
+ # ITEM
100
94
  # =========================================================
101
95
 
102
- class PurchaseTrns(BaseModel):
103
- tin: TIN
104
- bhfId: BHF
105
- lastReqDt: DT14
106
-
107
-
108
- class PurchaseItem(BaseModel):
109
- itemSeq: conint(ge=1)
110
- itemCd: str
111
- itemNm: str
112
- qty: condecimal(gt=0)
113
- prc: condecimal(ge=0)
114
- splyAmt: condecimal(ge=0)
115
- taxTyCd: Annotated[str, StringConstraints(pattern="^[A-E]$")]
116
- taxblAmt: condecimal(ge=0)
117
- taxAmt: condecimal(ge=0)
118
- totAmt: condecimal(ge=0)
96
+ class SaveItem(BaseModel):
97
+ itemCd: Annotated[str, StringConstraints(min_length=1)]
98
+ itemClsCd: Annotated[str, StringConstraints(min_length=1)]
99
+ itemTyCd: Annotated[str, StringConstraints(min_length=1)]
100
+ itemNm: Annotated[str, StringConstraints(min_length=1)]
101
+ itemStdNm: Optional[Annotated[str, ...]] = None # string or null
102
+ orgnNatCd: Annotated[str, StringConstraints(min_length=2, max_length=5)]
103
+ pkgUnitCd: Annotated[str, StringConstraints(min_length=1)]
104
+ qtyUnitCd: Annotated[str, StringConstraints(min_length=1)]
105
+ taxTyCd: Annotated[str, StringConstraints(min_length=1)]
106
+ dftPrc: condecimal(ge=0)
107
+ grpPrcL1: Optional[condecimal()] = None
108
+ grpPrcL2: Optional[condecimal()] = None
109
+ grpPrcL3: Optional[condecimal()] = None
110
+ grpPrcL4: Optional[condecimal()] = None
111
+ grpPrcL5: Optional[condecimal()] = None
112
+ btchNo: Optional[Annotated[str, ...]] = None # string or null
113
+ bcd: Optional[Annotated[str, ...]] = None # string or null
114
+ addInfo: Optional[Annotated[str, ...]] = None # string or null
115
+ sftyQty: Optional[condecimal()] = None
116
+ isrcAplcbYn: YN
117
+ useYn: YN
118
+ regrId: Annotated[str, StringConstraints(min_length=1)]
119
+ regrNm: Annotated[str, StringConstraints(min_length=1)]
120
+ modrId: Annotated[str, StringConstraints(min_length=1)] # REQUIRED in PHP
121
+ modrNm: Annotated[str, StringConstraints(min_length=1)] # REQUIRED in PHP
119
122
 
120
123
 
121
- class PurchaseTransaction(BaseModel):
122
- invcNo: conint(ge=1)
123
- spplrTin: str
124
- spplrNm: str
125
- pchsDt: DT8
126
- totItemCnt: conint(ge=1)
127
- totTaxblAmt: condecimal(ge=0)
128
- totTaxAmt: condecimal(ge=0)
129
- totAmt: condecimal(ge=0)
130
- regrId: str
131
- regrNm: str
132
- itemList: List[PurchaseItem]
124
+ class ItemComposition(BaseModel):
125
+ itemCd: Annotated[str, StringConstraints(min_length=1)]
126
+ cpstItemCd: Annotated[str, StringConstraints(min_length=1)]
127
+ cpstQty: condecimal(gt=0) # min(0.001) → gt=0 covers it
128
+ regrId: Annotated[str, StringConstraints(min_length=1)]
129
+ regrNm: Annotated[str, StringConstraints(min_length=1)]
130
+ modrId: Optional[str] = None
131
+ modrNm: Optional[str] = None
133
132
 
134
133
 
135
134
  # =========================================================
136
- # SALES
135
+ # IMPORTED ITEM
137
136
  # =========================================================
138
137
 
139
- class SalesItem(BaseModel):
138
+ class ImportItemUpdate(BaseModel):
139
+ taskCd: Annotated[str, StringConstraints(min_length=1)]
140
+ dclDe: Annotated[str, StringConstraints(min_length=8, max_length=14)]
140
141
  itemSeq: conint(ge=1)
141
- itemCd: str
142
- itemClsCd: str
143
- itemNm: str
144
- qty: condecimal(gt=0)
145
- prc: condecimal(ge=0)
146
- splyAmt: condecimal(ge=0)
147
- taxTyCd: Annotated[str, StringConstraints(pattern="^[A-E]$")]
148
- taxblAmt: condecimal(ge=0)
149
- taxAmt: condecimal(ge=0)
150
- totAmt: condecimal(ge=0)
151
-
152
-
153
- class SalesTrns(BaseModel):
154
- tin: TIN
155
- bhfId: BHF
156
- lastReqDt: DT14
157
-
158
-
159
- class SelectSalesTrns(BaseModel):
160
- tin: TIN
161
- bhfId: BHF
162
- lastReqDt: DT14
142
+ hsCd: Annotated[str, StringConstraints(min_length=1, max_length=17)]
143
+ itemClsCd: Annotated[str, StringConstraints(min_length=1, max_length=10)]
144
+ itemCd: Annotated[str, StringConstraints(min_length=1, max_length=20)]
145
+ imptItemSttsCd: Annotated[str, StringConstraints(min_length=1)]
146
+ modrId: Annotated[str, StringConstraints(min_length=1)]
147
+ modrNm: Annotated[str, StringConstraints(min_length=1)]
148
+ remark: Optional[str] = None
163
149
 
164
150
 
165
- class SalesTransaction(BaseModel):
166
- invcNo: conint(ge=1)
167
- custTin: str
168
- custNm: str
169
-
170
- salesTyCd: Annotated[str, StringConstraints(pattern="^[NR]$")]
171
- rcptTyCd: Annotated[str, StringConstraints(pattern="^[RPC]$")]
172
- pmtTyCd: Annotated[str, StringConstraints(pattern=r"^\d{2}$")]
173
- salesSttsCd: Annotated[str, StringConstraints(pattern="^(01|02|03)$")]
174
-
175
- cfmDt: DT14
176
- salesDt: DT8
151
+ # =========================================================
152
+ # STOCK
153
+ # =========================================================
177
154
 
178
- totItemCnt: conint(ge=1)
179
- totTaxblAmt: condecimal(ge=0)
180
- totTaxAmt: condecimal(ge=0)
181
- totAmt: condecimal(ge=0)
155
+ class StockMaster(BaseModel):
156
+ itemCd: Annotated[str, StringConstraints(min_length=1, max_length=20)]
157
+ rsdQty: condecimal(ge=0) # Remaining quantity
158
+ regrId: Annotated[str, StringConstraints(min_length=1, max_length=20)]
159
+ regrNm: Annotated[str, StringConstraints(min_length=1, max_length=60)]
160
+ modrId: Annotated[str, StringConstraints(min_length=1, max_length=20)]
161
+ modrNm: Annotated[str, StringConstraints(min_length=1, max_length=60)]
182
162
 
183
- regrId: str
184
- regrNm: str
185
163
 
186
- itemList: List[SalesItem]
164
+ # Purchase Transaction Item (for insertTrnsPurchase)
165
+ class InsertTrnsPurchaseItem(BaseModel):
166
+ itemSeq: conint(ge=1)
167
+ itemCd: Annotated[str, StringConstraints(min_length=1, max_length=20)]
168
+ itemClsCd: Annotated[str, StringConstraints(min_length=1, max_length=10)]
169
+ itemNm: Annotated[str, StringConstraints(min_length=1, max_length=200)]
170
+ bcd: Optional[Annotated[str, StringConstraints(max_length=20)]] = None
171
+ spplrItemClsCd: Optional[Annotated[str, StringConstraints(max_length=10)]] = None
172
+ spplrItemCd: Optional[Annotated[str, StringConstraints(max_length=20)]] = None
173
+ spplrItemNm: Optional[Annotated[str, StringConstraints(max_length=200)]] = None
174
+ pkgUnitCd: Annotated[str, StringConstraints(max_length=5)]
175
+ pkg: condecimal()
176
+ qtyUnitCd: Annotated[str, StringConstraints(max_length=5)]
177
+ qty: condecimal()
178
+ prc: condecimal()
179
+ splyAmt: condecimal()
180
+ dcRt: condecimal()
181
+ dcAmt: condecimal()
182
+ taxblAmt: condecimal()
183
+ taxTyCd: Annotated[str, StringConstraints(max_length=5)]
184
+ taxAmt: condecimal()
185
+ totAmt: condecimal()
186
+ itemExprDt: Optional[FLEX_DATE] = None # 8–14 digits
187
+
188
+
189
+ class InsertTrnsPurchase(BaseModel):
190
+ spplrTin: Optional[Annotated[str, StringConstraints(min_length=11, max_length=11)]] = None
191
+ invcNo: conint(ge=0)
192
+ orgInvcNo: conint(ge=0)
193
+ spplrBhfId: Optional[Annotated[str, StringConstraints(min_length=2, max_length=2)]] = None
194
+ spplrNm: Optional[Annotated[str, StringConstraints(max_length=60)]] = None
195
+ spplrInvcNo: Optional[conint(ge=0)] = None
196
+ regTyCd: Annotated[str, StringConstraints(min_length=1, max_length=5)]
197
+ pchsTyCd: Annotated[str, StringConstraints(min_length=1, max_length=5)]
198
+ rcptTyCd: Annotated[str, StringConstraints(min_length=1, max_length=5)]
199
+ pmtTyCd: Annotated[str, StringConstraints(min_length=1, max_length=5)]
200
+ pchsSttsCd: Annotated[str, StringConstraints(min_length=1, max_length=5)]
201
+ cfmDt: Optional[FLEX_DATE] = None
202
+ wrhsDt: Optional[FLEX_DATE] = None
203
+ cnclReqDt: Optional[FLEX_DATE] = None
204
+ cnclDt: Optional[FLEX_DATE] = None
205
+ rfdDt: Optional[FLEX_DATE] = None
206
+ pchsDt: Optional[FLEX_DATE] = None
207
+ totItemCnt: conint(ge=0)
208
+ taxblAmtA: condecimal()
209
+ taxblAmtB: condecimal()
210
+ taxblAmtC: condecimal()
211
+ taxblAmtD: condecimal()
212
+ taxblAmtE: condecimal()
213
+ taxRtA: condecimal()
214
+ taxRtB: condecimal()
215
+ taxRtC: condecimal()
216
+ taxRtD: condecimal()
217
+ taxRtE: condecimal()
218
+ taxAmtA: condecimal()
219
+ taxAmtB: condecimal()
220
+ taxAmtC: condecimal()
221
+ taxAmtD: condecimal()
222
+ taxAmtE: condecimal()
223
+ totTaxblAmt: condecimal()
224
+ totTaxAmt: condecimal()
225
+ totAmt: condecimal()
226
+ remark: Optional[Annotated[str, StringConstraints(max_length=400)]] = None
227
+ regrId: Annotated[str, StringConstraints(max_length=20)]
228
+ regrNm: Annotated[str, StringConstraints(max_length=60)]
229
+ modrId: Annotated[str, StringConstraints(max_length=20)]
230
+ modrNm: Annotated[str, StringConstraints(max_length=60)]
231
+ itemList: List[InsertTrnsPurchaseItem]
232
+
233
+
234
+ # Stock IO Item
235
+ class SaveStockIOItem(BaseModel):
236
+ itemSeq: conint(ge=1)
237
+ itemCd: Annotated[str, StringConstraints(min_length=1, max_length=20)]
238
+ itemClsCd: Annotated[str, StringConstraints(min_length=1, max_length=10)]
239
+ itemNm: Annotated[str, StringConstraints(min_length=1, max_length=200)]
240
+ bcd: Optional[Annotated[str, StringConstraints(max_length=20)]] = None
241
+ pkgUnitCd: Annotated[str, StringConstraints(max_length=5)]
242
+ pkg: condecimal()
243
+ qtyUnitCd: Annotated[str, StringConstraints(max_length=5)]
244
+ qty: condecimal()
245
+ itemExprDt: Optional[DT8] = None # YYYYMMDD only
246
+ prc: condecimal()
247
+ splyAmt: condecimal()
248
+ totDcAmt: condecimal()
249
+ taxblAmt: condecimal()
250
+ taxTyCd: Annotated[str, StringConstraints(max_length=5)]
251
+ taxAmt: condecimal()
252
+ totAmt: condecimal()
253
+
254
+
255
+ class SaveStockIO(BaseModel):
256
+ tin: Annotated[str, StringConstraints(min_length=11, max_length=11)]
257
+ bhfId: Annotated[str, StringConstraints(min_length=2, max_length=2)]
258
+ sarNo: conint(ge=0)
259
+ orgSarNo: conint(ge=0)
260
+ regTyCd: Annotated[str, StringConstraints(min_length=1, max_length=5)]
261
+ custTin: Optional[Annotated[str, StringConstraints(min_length=11, max_length=11)]] = None
262
+ custNm: Optional[Annotated[str, StringConstraints(max_length=100)]] = None
263
+ custBhfId: Optional[Annotated[str, StringConstraints(min_length=2, max_length=2)]] = None
264
+ sarTyCd: Annotated[str, StringConstraints(min_length=1, max_length=5)]
265
+ ocrnDt: DT8 # YYYYMMDD
266
+ totItemCnt: conint(ge=0)
267
+ totTaxblAmt: condecimal()
268
+ totTaxAmt: condecimal()
269
+ totAmt: condecimal()
270
+ remark: Optional[Annotated[str, StringConstraints(max_length=400)]] = None
271
+ regrId: Annotated[str, StringConstraints(max_length=20)]
272
+ regrNm: Annotated[str, StringConstraints(max_length=60)]
273
+ modrId: Annotated[str, StringConstraints(max_length=20)]
274
+ modrNm: Annotated[str, StringConstraints(max_length=60)]
275
+ itemList: List[SaveStockIOItem]
187
276
 
188
277
 
189
278
  # =========================================================
190
- # STOCK
279
+ # VALIDATOR MAP
191
280
  # =========================================================
192
281
 
193
- class MoveList(BaseModel):
194
- tin: TIN
195
- bhfId: BHF
196
- lastReqDt: DT14
282
+ from .exceptions import ValidationException
197
283
 
284
+ SCHEMAS = {
285
+ # INITIALIZATION
286
+ "initialization": Initialization,
198
287
 
199
- class StockMaster(BaseModel):
200
- itemCd: str
201
- itemNm: str
202
- useYn: YN
203
- regrId: str
204
- regrNm: str
288
+ # COMMON
289
+ "lastReqOnly": LastReqOnly,
290
+ "custSearchReq": CustSearchReq,
291
+
292
+ # BRANCH
293
+ "branchCustomer": BranchCustomer,
294
+ "branchUser": BranchUser,
295
+ "branchInsurance": BranchInsurance,
296
+
297
+ # ITEM
298
+ "saveItem": SaveItem,
299
+ "itemComposition": ItemComposition,
205
300
 
301
+ # IMPORTED ITEM
302
+ "importItemUpdate": ImportItemUpdate,
206
303
 
207
- class StockIO(BaseModel):
208
- itemCd: str
209
- qty: condecimal(gt=0)
210
- ioTyCd: Annotated[str, StringConstraints(pattern="^[IO]$")]
211
- regrId: str
212
- regrNm: str
304
+ # STOCK
305
+ "stockMaster": StockMaster,
306
+ "insertTrnsPurchase": InsertTrnsPurchase,
307
+ "saveStockIO": SaveStockIO,
308
+ }
@@ -1,47 +1,21 @@
1
+ from typing import Dict, Any
1
2
  from pydantic import ValidationError
2
- from .schemas import *
3
+ from .schemas import SCHEMAS
3
4
  from .exceptions import ValidationException
4
5
 
5
6
 
6
- SCHEMAS = {
7
- # INIT
8
- "initialization": Initialization,
9
-
10
- # BASIC DATA
11
- "codeList": CodeList,
12
- "itemClsList": CodeList,
13
- "bhfList": BhfList,
14
- "noticeList": NoticeList,
15
- "taxpayerInfo": TaxpayerInfo,
16
- "customerList": CustomerList,
17
-
18
- # PURCHASE
19
- "purchaseTrns": PurchaseTrns,
20
- "purchaseTransaction": PurchaseTransaction,
21
-
22
- # SALES
23
- "salesTrns": SalesTrns,
24
- "selectSalesTrns": SelectSalesTrns,
25
- "salesTransaction": SalesTransaction,
26
-
27
- # STOCK
28
- "moveList": MoveList,
29
- "stockMaster": StockMaster,
30
- "stockIO": StockIO,
31
-
32
- # BRANCH
33
- "branchInsurance": BranchInsurance,
34
- "branchUserAccount": BranchUserAccount,
35
- "customerInfo": CustomerInfo,
36
- }
37
-
38
-
39
7
  class Validator:
40
- def validate(self, data: dict, schema: str) -> dict:
8
+ def validate(self, data: Dict[str, Any], schema: str) -> Dict[str, Any]:
41
9
  if schema not in SCHEMAS:
42
10
  raise ValueError(f"Validation schema '{schema}' not defined")
43
11
 
44
12
  try:
45
- return SCHEMAS[schema](**data).dict()
13
+ validated = SCHEMAS[schema](**data)
14
+ return validated.model_dump(mode='json') # Converts Decimals to floats
46
15
  except ValidationError as e:
47
- raise ValidationException("Validation failed", e.errors())
16
+ # Convert Pydantic errors to field:message dict like PHP
17
+ messages = {}
18
+ for error in e.errors():
19
+ field = ".".join(str(loc) for loc in error["loc"])
20
+ messages[field] = error["msg"]
21
+ raise ValidationException("Validation failed", messages)