Skip to content

Commit

Permalink
Merge pull request #20 from LayerXcom/feature/receipts
Browse files Browse the repository at this point in the history
feat: add receipts
naomasabit authored Jan 5, 2021
2 parents 07e671d + fbd1807 commit 7479a10
Showing 3 changed files with 177 additions and 1 deletion.
90 changes: 90 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import (
"encoding/json"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"path"
@@ -154,3 +155,92 @@ func (c *Client) call(ctx context.Context,

return oauth2Token, json.NewDecoder(r).Decode(&res)
}

func (c *Client) upload(ctx context.Context,
apiPath string,
oauth2Token *oauth2.Token,
queryParams url.Values,
postBody map[string]string,
fileName string,
file []byte,
res interface{},
) (*oauth2.Token, error) {
// url
u, err := url.Parse(c.config.APIEndpoint)
if err != nil {
return oauth2Token, err
}
u.Path = path.Join(u.Path, APIPath1, apiPath)
u.RawQuery = queryParams.Encode()
body := &bytes.Buffer{}
// form data
mw := multipart.NewWriter(body)
fw, err := mw.CreateFormFile("receipt", fileName)
if err != nil {
return oauth2Token, err
}
_, err = io.Copy(fw, bytes.NewReader(file))
if err != nil {
return oauth2Token, err
}
for k, v := range postBody {
err = mw.WriteField(k, v)
if err != nil {
return oauth2Token, err
}
}
contentType := mw.FormDataContentType()
err = mw.Close()
if err != nil {
return oauth2Token, err
}
// request
req, err := http.NewRequest(http.MethodPost, u.String(), body)
if err != nil {
return oauth2Token, err
}
// header Content-Type
req.Header.Set("Content-Type", contentType)
req = req.WithContext(ctx)
tokenSource := c.config.Oauth2.TokenSource(ctx, oauth2Token)
httpClient := oauth2.NewClient(ctx, tokenSource)
response, err := httpClient.Do(req)
if err != nil {
return oauth2Token, err
}
defer response.Body.Close()
c.logf("[freee] %s: %s", HeaderXFreeeRequestID, response.Header.Get(HeaderXFreeeRequestID))
c.logf("[freee] %s: %v %v%v", response.Status, req.Method, req.URL.Host, req.URL.Path)

var r io.Reader = response.Body
// Parse freee API errors
code := response.StatusCode
if code >= http.StatusBadRequest {
byt, err := ioutil.ReadAll(r)
if err != nil {
// error occured, but ignored.
c.logf("[freee] HTTP response body: %v", err)
}
res := &Error{
StatusCode: code,
RawError: string(byt),
}
// Check if re-authorization is required
if code == http.StatusUnauthorized {
var e UnauthorizedError
if err := json.NewDecoder(bytes.NewReader(byt)).Decode(&e); err != nil {
c.logf("[freee] HTTP response body: %v", err)
return oauth2Token, res
}
if e.Code == UnauthorizedCodeInvalidAccessToken ||
e.Code == UnauthorizedCodeExpiredAccessToken {
res.IsAuthorizationRequired = true
}
}
return oauth2Token, res
}
if res == nil {
return oauth2Token, nil
}
return oauth2Token, json.NewDecoder(r).Decode(&res)
}
3 changes: 2 additions & 1 deletion deals.go
Original file line number Diff line number Diff line change
@@ -158,7 +158,7 @@ type DealCreateParamsPayments struct {
// will change when the set of required properties is changed
func NewDealCreateParams(issueDate string, type_ string, companyID int32,
dueDate string, partnerID int32, partnerCode string, refNumber string,
details *[]DealCreateParamsDetails) *DealCreateParams {
receiptIDs []int32, details *[]DealCreateParamsDetails) *DealCreateParams {
this := DealCreateParams{}
this.IssueDate = issueDate
this.Type = type_
@@ -167,6 +167,7 @@ func NewDealCreateParams(issueDate string, type_ string, companyID int32,
this.PartnerID = partnerID
this.PartnerCode = partnerCode
this.RefNumber = refNumber
this.ReceiptIDs = receiptIDs
this.Details = details
return &this
}
85 changes: 85 additions & 0 deletions receipts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package freee

import (
"context"
"golang.org/x/oauth2"
"strconv"
)

const (
APIPathReceipts = "receipts"
)

type CreateReceiptParams struct {
// 事業所ID
CompanyID int32 `json:"company_id"`
// メモ (255文字以内)
Description string `json:"description,omitempty"`
// 取引日 (yyyy-mm-dd)
IssueDate string `json:"issue_date"`
// 証憑ファイル
Receipt []byte `json:"receipt"`
}

// NewReceiptUpdateParams instantiates a new ReceiptUpdateParams object
// This constructor will assign default values to properties that have it defined,
// and makes sure properties required by API are set, but the set of arguments
// will change when the set of required properties is changed
func NewCreateReceiptParams(companyID int32, description string, issueDate string, receipt []byte) *CreateReceiptParams {
this := CreateReceiptParams{}
this.CompanyID = companyID
this.IssueDate = issueDate
this.Description = description
this.Receipt = receipt
return &this
}

type ReceiptResponse struct {
Receipt Receipt `json:"receipt"`
}

type Receipt struct {
// 証憑ID
ID int32 `json:"id"`
// ステータス(unconfirmed:確認待ち、confirmed:確認済み、deleted:削除済み、ignored:無視)
Status string `json:"status"`
// メモ
Description string `json:"description,omitempty"`
// MIMEタイプ
MimeType string `json:"mime_type"`
// 発生日
IssueDate string `json:"issue_date,omitempty"`
// アップロード元種別
Origin string `json:"origin"`
// 作成日時(ISO8601形式)
CreatedAt string `json:"created_at"`
// ファイルのダウンロードURL(freeeにログインした状態でのみ閲覧可能です。) <br> <br> file_srcは廃止予定の属性になります。<br> file_srcに替わり、証憑ファイルのダウンロード APIをご利用ください。<br> 証憑ファイルのダウンロードAPIを利用することで、以下のようになります。 <ul> <li>アプリケーション利用者はfreee APIアプリケーションにログインしていれば、証憑ダウンロード毎にfreeeに改めてログインすることなくファイルが参照できるようになります。</li> </ul>
FileSrc string `json:"file_src"`
User UserCreatedReceipt `json:"user"`
}

type UserCreatedReceipt struct {
// ユーザーID
ID int32 `json:"id"`
// メールアドレス
Email string `json:"email"`
// 表示名
DisplayName string `json:"display_name,omitempty"`
}

func (c *Client) CreateReceipt(
ctx context.Context, oauth2Token *oauth2.Token,
params CreateReceiptParams,
receiptName string,
) (*ReceiptResponse, *oauth2.Token, error) {
request := map[string]string{}
request["company_id"] = strconv.Itoa(int(params.CompanyID))
request["description"] = params.Description
request["issue_date"] = params.IssueDate
var result ReceiptResponse
oauth2Token, err := c.upload(ctx, APIPathReceipts, oauth2Token, nil, request, receiptName, params.Receipt, &result)
if err != nil {
return nil, oauth2Token, err
}
return &result, oauth2Token, nil
}

0 comments on commit 7479a10

Please sign in to comment.