From 2b4773b67e945b607427c2d2036f3bf5757e8925 Mon Sep 17 00:00:00 2001 From: dennis Date: Sun, 27 Aug 2023 22:48:30 +0800 Subject: [PATCH] Initial commit --- FeeAuditJSON.go | 247 +++++++++++++++++++++++++++++++++++++++++++++++ FeeAuditUtils.go | 219 +++++++++++++++++++++++++++++++++++++++++ go.mod | 5 + go.sum | 2 + 4 files changed, 473 insertions(+) create mode 100644 FeeAuditJSON.go create mode 100644 FeeAuditUtils.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/FeeAuditJSON.go b/FeeAuditJSON.go new file mode 100644 index 0000000..37f6400 --- /dev/null +++ b/FeeAuditJSON.go @@ -0,0 +1,247 @@ +package mohwhelper + +// WriteoffRequest 是 writeoff 的 Request +type WriteoffRequest struct { + UnitNo string `json:"unitNo"` // 服務單位代碼 + RequestAt string `json:"requestDt"` // 申請日期時間 + SourceSystem string `json:"sourceSystem"` // 來源系統別 + ApData string `json:"apdata"` // 申請內容 + Checksum string `json:"checksum"` // 校驗碼 +} + +// WriteoffResponse 是 writeoff 的 Response +type WriteoffResponse struct { + ReturnCode int `json:"rtncode"` // 回覆結果代碼 + ResponseAt string `json:"responseDt"` // 回覆日期時間 + ErrorMessage string `json:"errmsg"` // 回覆訊息 + Result string `json:"result"` // 回覆明細 + Checksum string `json:"checksum"` // 校驗碼 + ReturnSeq string `json:"rtnSeq"` // 回覆序號 +} + +// FeeApplyUpload 是 FeeApply 的傳送資料 +type FeeApplyUpload struct { + ApplyInfo ApplyInfo `json:"apply_info"` // 申報資料 +} + +// ApplyInfo 是 FeeApplyUpload 的單筆資料 +type ApplyInfo struct { + WriteoffYYYYMM string `json:"writeoff_yyyymm"` // 支審年月 + TransNo string `json:"trans_no"` // 交易序號 + Records int `json:"records"` // 服務記錄筆數 + Amount int `json:"amount"` // 服務記錄金額 + Cases int `json:"cases"` // 申請個案數 + CaseSvceRecords []CaseSvceRecord `json:"case_svc_records"` // 個案服務記錄 +} + +// CaseSvcRecord 是個案服務記錄 +type CaseSvceRecord struct { + ObjID string `json:"objid"` // 識別碼 + IDN string `json:"idn,omitempty"` // 個案身份證字號 + SvcAt string `json:"svc_dt,omitempty"` // 服務日期 + GovItemCode string `json:"gov_item_cd,omitempty"` // 照顧組合代碼 + SvcFeeType string `json:"svc_fee_tp,omitempty"` // 服務類別 + Price int `json:"price,omitempty"` // 單價 + Amount int `json:"amount,omitempty"` // 數量 + SvcUserNo1 string `json:"svc_user_no1,omitempty"` // 照顧服務員帳號1 + SvcUserNo2 string `json:"svc_user_no2,omitempty"` // 照顧服務員帳號2 + SvcUserNo3 string `json:"svc_user_no3,omitempty"` // 照顧服務員帳號3 + SvcUserNo4 string `json:"svc_user_no4,omitempty"` // 照顧服務員帳號4 + SvcUserNo5 string `json:"svc_user_no5,omitempty"` // 照顧服務員帳號5 + StartHH string `json:"start_hh,omitempty"` // 起始時段-小時 + StartMM string `json:"start_mm,omitempty"` // 起始時段-分鐘 + EndHH string `json:"end_hh,omitempty"` // 結束時段-小時 + EndMM string `json:"end_mm,omitempty"` // 結束時段-分鐘 + Remark string `json:"remark,omitempty"` // 備註 + LastSvc string `json:"last_svc,omitempty"` // 臨終日照顧 + Addr1 string `json:"addr1,omitempty"` // 出發地 + Addr2 string `json:"addr2,omitempty"` // 目的地 + CarNo string `json:"car_no,omitempty"` // 車號 + Driver string `json:"driver,omitempty"` // 駕駛員 + ApplyAA03 string `json:"apply_aa03,omitempty"` // 是否申報AA03 + SvcItem string `json:"svc_item,omitempty"` // 服務項目 + SvcItemOther string `json:"svc_item_other,omitempty"` // 服務項目-其他 + SvcPeople string `json:"svc_people,omitempty"` // 服務對象 + SvcContent string `json:"svc_content,omitempty"` // 服務內容 + SvcUnit string `json:"svc_unit,omitempty"` // 提供專業服務單位 + ApplyAA09 string `json:"apply_aa09,omitempty"` // 是否申報AA09 + AA10Status string `json:"aa10_status,omitempty"` // AA10申報狀態 + MissedVisit string `json:"missed_visit,omitempty"` // 訪視/服務未遇 + SvcEndDt string `json:"svc_end_dt,omitempty"` // 服務結束日期 +} + +// FeeApplyResult 是 FeeApply 的 Response.result +type FeeApplyResult struct { + ProcessNumber int `json:"proc_num"` // 處理筆數 + SuccessNumber int `json:"succ_num"` // 上傳成功筆數 + ErrorNumber int `json:"err_num"` // 上傳失敗筆數 + ErrorRecords []ErrorRecord `json:"err_record"` // 錯誤服務記錄 +} + +// ErrorRecord 是錯誤服務記錄 +type ErrorRecord struct { + ObjID string `json:"objid"` // 識別碼 + ErrorInfos []ErrorInfo `json:"err_info"` // 錯誤訊息 +} + +// ErrorInfo 是錯誤訊息 +type ErrorInfo struct { + ErrorCode string `json:"err_code"` // 錯誤碼 + ErrorMessage string `json:"err_message"` // 錯誤原因 +} + +// ObjDelUpload 是 ObjDel 的傳送資料 +type ObjDelUpload struct { + SvcDelInfo SvcDelInfo `json:"svcdel_info"` // 刪除資料 +} + +// SvcDelInfo 是刪除資料 +type SvcDelInfo struct { + WriteoffYYYYMM string `json:"writeoff_yyyymm"` // 支審年月 + TransNo string `json:"trans_no"` // 交易序號 + Records int `json:"records"` // 服務記錄筆數 + CaseSvceRecords []CaseSvceRecord `json:"case_svc_records"` // 個案服務記錄 +} + +// AppCompletionNoticeUpload 是 AppCompletionNotice 的傳送資料 +type AppCompletionNoticeUpload struct { + FinishInfo FinishInfo `json:"finish_info"` // 申報確認資料 +} + +// FinishInfo 是申報確認資料 +type FinishInfo struct { + WriteoffYYYYMM string `json:"writeoff_yyyymm"` // 支審年月 + TransNo string `json:"trans_no"` // 交易序號 + CityInfos []CityInfo `json:"city_info"` // 縣市案號資訊 +} + +// CityInfo 是縣市案號資訊 +type CityInfo struct { + CityCode string `json:"city_cd"` // 縣市代碼 + CaseNoInfos []CaseNoInfo `json:"case_no_info"` // 案件資訊 +} + +// CaseNoInfo 是案件資訊 +type CaseNoInfo struct { + CaseNo string `json:"case_no"` // 案件編號 + Status string `json:"status,omitempty"` // 核銷狀況 + DocVer string `json:"doc_ver,omitempty"` // 總表版次 + AccNum string `json:"acc_num,omitempty"` // 簽證編號 +} + +// AppResultQueryUpload 是 AppResultQuery 的傳送資料 +type AppResultQueryUpload struct { + AppResultQueryInfo AppResultQueryInfo `json:"app_result_query_info"` // 查詢輸入資訊 +} + +// AppResultQueryInfo 是查詢輸入資訊 +type AppResultQueryInfo struct { + WriteoffYYYYMM string `json:"writeoff_yyyymm"` // 支審年月 + TransNo string `json:"trans_no"` // 交易序號 + QueryType string `json:"query_type"` // 查詢類別 + CityCode string `json:"city_cd,omitempty"` // 縣市代碼 + CaseNo string `json:"case_no,omitempty"` // 核銷案號 +} + +// AppResultQueryResult 是 AppResultQuery 的 Response.result +type AppResultQueryResult struct { + CityInfos []CityInfo `json:"city_info,omitempty"` // 縣市案件資訊 + WebapiProcessInfos []WebapiProcessInfo `json:"webapi_process_info,omitempty"` // API 執行結果資料 + CaseNo string `json:"case_no,omitempty"` // 核銷案號 + Records int `json:"records,omitempty"` // 服務記錄筆數 + Cases int `json:"cases,omitempty"` // 個案數 + Amount int `json:"amount,omitempty"` // 申請核銷金額 + AuditMan string `json:"audit_man,omitempty"` // 承辦人員 + AuditReason string `json:"audit_reason,omitempty"` // 承辦審核意見 + DocVer string `json:"doc_ver,omitempty"` // 總表版次 + VerDate string `json:"ver_dt,omitempty"` // 版次時間 + ApproveCasesNum int `json:"approve_cases_num,omitempty"` // 核定個案數 + ApproveRecordCount int `json:"approve_record_count,omitempty"` // 核定服務記錄數 + ApproveFee int `json:"approve_fee,omitempty"` // 核定金額 + ASvcFee int `json:"a_svc_fee,omitempty"` // 政策鼓勵金額 + TempPaymentStatus string `json:"temp_payment_status,omitempty"` // 暫付申請狀態 + TempPaymentFee int `json:"temp_payment_fee,omitempty"` // 分案暫付金額 + TempPaymentDocUrl string `json:"temp_payment_doc_url,omitempty"` // 暫付總表下載路徑 + CaseSummaryNoticeUrl string `json:"case_summary_notice_url,omitempty"` // 總表下載路徑 + CaseSvcListUrl string `json:"case_svc_list_url,omitempty"` // 清冊路徑 + CaseSvcListExcelUrl string `json:"case_svc_list_excel_url,omitempty"` // 清冊 EXCEL 下載路徑 + CaseASvcListUrl string `json:"case_a_svc_list_url,omitempty"` // A 碼清冊路徑 + CaseASvcListExcelUrl string `json:"case_a_svc_list_excel_url,omitempty"` // A 碼清冊 EXCEL 下載路徑 + CaseErrListUrl string `json:"case_err_list_url,omitempty"` // 申請記錄不通過清冊路徑 + CaseErrListExcelUrl string `json:"case_err_list_excel_url,omitempty"` // 申請記錄不通過 EXCEL 清冊路徑 + TransNos []string `json:"trans_nos,omitempty"` // 分案已處理之單號申請單單號 + IncInAcc int `json:"inc_in_acc,omitempty"` // 核增金額 + IncInReason string `json:"inc_in_reason,omitempty"` // 核增原因 + DecInAcc int `json:"dec_in_acc,omitempty"` // 核減金額 + DecInReason string `json:"dec_in_reason,omitempty"` //核減原因 + ApproveRecords []ApproveRecord `json:"approve_records,omitempty"` // 審核通過服務記錄 + ErrorRecords []ExceptionRecord `json:"err_records,omitempty"` // 錯誤服務記錄 + ASvcRecords []ASvcRecord `json:"a_svc_records"` // A 碼加成資料區 +} + +// WebapiProcessInfo 是 API 執行結果資料 +type WebapiProcessInfo struct { + Function string `json:"function"` // API Function + SourceSystem string `json:"source_system"` // 來源系統別 + TransNo string `json:"trans_no"` // 交易序號 + Status string `json:"status"` // API 執行狀態 + BatchProcResult string `json:"batch_proc_result"` // 批次處理結果 + BatchProcNum int `json:"batch_proc_num"` // 批次處理筆數 + BatchSuccNum int `json:"batch_succ_num"` // 批次處理成功筆數 + BatchErrNum int `json:"batch_err_num"` // 批次處理失敗筆數 + ExceptionRecords []ExceptionRecord `json:"exception_records"` // 分案異常資料 + DeleteRecords []string `json:"delete_records"` // 服務紀錄刪除成功資料 + DeleteExceptionRecords []ExceptionRecord `json:"delete_exception_records"` // 服務紀錄刪除失敗資料 +} + +// ExceptionRecord 是異常資料 +type ExceptionRecord struct { + SourceSystem string `json:"source_system,omitempty"` // 來源系統別 + ObjID string `json:"objid,omitempty"` // 識別碼 + TransNo string `json:"trans_no,omitempty"` // 交易序號 + ErrorCode string `json:"err_code"` // 錯誤碼 + ErrorMessage string `json:"err_message"` // 錯誤原因 +} + +// ApproveRecord 是審核通過服務記錄 +type ApproveRecord struct { + SourceSystem string `json:"source_system"` // 來源系統別 + ObjID string `json:"objid"` // 識別碼 + TransNo string `json:"trans_no"` // 交易序號 + Price int `json:"price"` // 單價 + Copayment int `json:"copayment"` // 自付額 +} + +// ASvcRecord 是 A 碼加成資料區 +type ASvcRecord struct { + RefSourceSystem string `json:"ref_source_system"` // 審核通過服務記錄來源系統別 + RefObjID string `json:"ref_objid"` // 審核通過服務記錄識別碼 + AGovItemCode string `json:"a_gov_item_cd"` // A 碼 + Price int `json:"price"` // 單價 +} + +// AppCancelUpload 是 AppCancel 的傳送資料 +type AppCancelUpload struct { + CancelInfo CancelInfo `json:"cancel_info"` // 服務單位撤回資料 + +} + +// CancelInfo 是服務單位撤回資料 +type CancelInfo struct { + WriteoffYYYYMM string `json:"writeoff_yyyymm"` // 支審年月 + CityCode string `json:"city_cd,omitempty"` // 縣市代碼 + CaseNo string `json:"case_no,omitempty"` // 核銷案號 + TransNo string `json:"trans_no"` // 交易序號 +} + +// CancelResultResponseUpload 是 CancelResultResponse 的傳送資料 +type CancelResultResponseUpload struct { + CancelResultResponseInfo CancelResultResponseInfo `json:"CancelResultResponse_info"` // 取消交易單結果回報資料 +} + +// CancelResultResponseInfo 是取消交易單結果回報資料 +type CancelResultResponseInfo struct { + WriteoffYYYYMM string `json:"writeoff_yyyymm"` // 支審年月 + TransNo string `json:"trans_no"` // 交易序號 + CancelTransNo string `json:"cancel_trans_no"` // 所要取消結果回報之交易序號 +} diff --git a/FeeAuditUtils.go b/FeeAuditUtils.go new file mode 100644 index 0000000..22fc665 --- /dev/null +++ b/FeeAuditUtils.go @@ -0,0 +1,219 @@ +package mohwhelper + +import ( + "bytes" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "io" + "math" + "net/http" + "os" + "time" + + "gitlab-ce.niaulang.com/niau-lang/golanghelper" +) + +type FeeAuditUtils struct { + UnitNo string + RequestAt string + SourceSystem string + Hash string + Url string + Cert []byte +} + +func NewFeeAuditUtils(unitNo, sourceSystem, hash, url, certPath string) (feeAuditUtils FeeAuditUtils, err error) { + stringutils := golanghelper.StringUtils{} + if stringutils.IsEmpty(unitNo) || stringutils.IsEmpty(sourceSystem) || stringutils.IsEmpty(hash) || + stringutils.IsEmpty(url) || stringutils.IsEmpty(certPath) { + err = errors.New("Invalid params") + } else { + feeAuditUtils.Cert, err = os.ReadFile(certPath) + if err != nil { + return + } + + feeAuditUtils.UnitNo = unitNo + feeAuditUtils.SourceSystem = sourceSystem + feeAuditUtils.Hash = hash + feeAuditUtils.Url = url + feeAuditUtils.RequestAt = time.Now().Format("20060102150405") + } + + return +} + +// getChecksum 用 apData 來取得校驗碼 +func (f *FeeAuditUtils) getChecksum(apData string) string { + apDataBytes := []byte(apData) + timeBytes := []byte(f.RequestAt) + hashBytes := []byte(f.Hash) + + timeByteLen := float64(len(timeBytes)) + hashByteLen := float64(len(hashBytes)) + + var sum int + var m1 int + var m2 int + + for i := 0; i < len(apDataBytes); i++ { + m1 = int(math.Mod(float64(i), hashByteLen)) + m2 = int(math.Mod(float64(i), timeByteLen)) + sum += int(apDataBytes[i])*int(hashBytes[m1]) + int(timeBytes[m2])*int(hashBytes[m1]) + + if sum>>16 > 0 { + sum = (sum >> 16) + (sum & 0xFFFF) + } + } + + hex := fmt.Sprintf("%X", sum) + + var stringutils golanghelper.StringUtils + return stringutils.LeftPad(hex, 4, "0") +} + +// httpsPost 用來上傳 WriteoffResponse +func (f *FeeAuditUtils) httpsPost(funcName string, writeoffRequest WriteoffRequest) (writeoffResponse WriteoffResponse, err error) { + data, err := json.Marshal(&writeoffRequest) + if err != nil { + return + } + + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(f.Cert) + + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: caCertPool, + }, + }, + } + + request, err := http.NewRequest("POST", f.Url+"/"+funcName, bytes.NewBuffer(data)) + if err != nil { + return + } + + request.Header.Set("Content-Type", "application/json; charset=UTF-8") + + response, err := client.Do(request) + if err != nil { + return + } + defer response.Body.Close() + + responseData, err := io.ReadAll(response.Body) + if err != nil { + return + } + + err = json.Unmarshal(responseData, &writeoffResponse) + + return +} + +// CreateRequest 用來産生 WirteoffRequest +func (f *FeeAuditUtils) NewRequest(data []byte) WriteoffRequest { + apData := base64.StdEncoding.EncodeToString(data) + + checksum := f.getChecksum(apData) + + return WriteoffRequest{ + UnitNo: f.UnitNo, + RequestAt: f.RequestAt, + SourceSystem: f.SourceSystem, + ApData: apData, + Checksum: checksum, + } +} + +// SendFeeApply 傳送服務記錄申報 +func (f *FeeAuditUtils) SendFeeApply(writeoffRequest WriteoffRequest) (feeApplyResult FeeApplyResult, err error) { + //uploadData, err := json.Marshal(&feeApply) + //if err != nil { + // return + //} + + writeoffResponse, err := f.httpsPost("FeeApply", writeoffRequest) + if err != nil { + return + } + + resultData, err := base64.StdEncoding.DecodeString(writeoffResponse.Result) + + err = json.Unmarshal(resultData, &feeApplyResult) + + return +} + +// SendObjDel 傳送服務紀錄刪除 +func (f *FeeAuditUtils) SendObjDel(writeoffRequest WriteoffRequest) (err error) { + //uploadData, err := json.Marshal(&objDel) + //if err != nil { + // return + //} + + _, err = f.httpsPost("ObjDel", writeoffRequest) + + return +} + +// SendAppCompletionNotice 傳送申報確認通知 +func (f *FeeAuditUtils) SendAppCompletionNotice(writeoffRequest WriteoffRequest) (err error) { + //uploadData, err := json.Marshal(&appCompletionNotice) + //if err != nil { + // return + //} + + _, err = f.httpsPost("appCompletionNotice", writeoffRequest) + + return +} + +// SendAppResultQuery 傳送「服務單位各分案審核狀態查詢」或「分案審核明細查詢」 +func (f *FeeAuditUtils) SendAppResultQuery(writeoffRequest WriteoffRequest) (appResultQueryResult AppResultQueryResult, err error) { + //uploadData, err := json.Marshal(&appResultQuery) + //if err != nil { + // return + //} + + writeoffResponse, err := f.httpsPost("appResultQuery", writeoffRequest) + if err != nil { + return + } + + resultData, err := base64.StdEncoding.DecodeString(writeoffResponse.Result) + + err = json.Unmarshal(resultData, &appResultQueryResult) + + return +} + +// SendAppCancel 傳送撤回服務記錄 +func (f *FeeAuditUtils) SendAppCancel(writeoffRequest WriteoffRequest) (err error) { + //uploadData, err := json.Marshal(&appCancel) + //if err != nil { + // return + //} + + _, err = f.httpsPost("appCancel", writeoffRequest) + + return +} + +// SendCancelResultResponse 傳送取消交易單處理結果回報 +func (f *FeeAuditUtils) SendCancelResultResponse(writeoffRequest WriteoffRequest) (err error) { + //uploadData, err := json.Marshal(&cancelResultResponse) + //if err != nil { + // return + //} + + _, err = f.httpsPost("CancelResultResponse", writeoffRequest) + + return +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b085eaf --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module gitlab-ce.niaulang.com/niau-lang/mohwhelper + +go 1.20 + +require gitlab-ce.niaulang.com/niau-lang/golanghelper v0.1.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f5445d3 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +gitlab-ce.niaulang.com/niau-lang/golanghelper v0.1.0 h1:DTLEIXzWWZVfHXA9wUNwfjTdqAdfTq3q+pPzQltV5kE= +gitlab-ce.niaulang.com/niau-lang/golanghelper v0.1.0/go.mod h1:b6JygESiH0jydmjtaHz6YucsW7YAkxQBBbeHSNFw/Ag=