vfd

package module
v0.0.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2023 License: MIT Imports: 21 Imported by: 0

README

vfdcloud/vfd a fully compliant golang implementation of the VFD API as specified by the Tanzania Revenue Authority (TRA).

The library currently supports

  • Client Registration
  • Token Fetching
  • Receipt Posting
  • Z Report Posting

You can also generate the receipt/z report in form of xml file as specified by the TRA. Also you can specify the location of the xml file and post it to TRA.

The library is used to power multiple platform in real world scenarios. So yes it has been tested in some real world environment. Still some improvements can be done and contributions are welcome.

Installation

 go get github.com/vfdcloud/vfd

Usage

package main

import (
    "fmt"
    "github.com/vfdcloud/vfd"
	"github.com/vfdcloud/vfd/pkg/env"
)

// Fetching Access Token
func main(){
	tokenURL := vfd.RequestURL(env.DEV,vfd.FetchTokenAction)
	request := &vfd.TokenRequest{
		Username:  "",
		Password:  "",
		GrantType: "",
	}
	response, err := vfd.FetchToken(context.Background(), tokenURL, request)
	if err != nil {
		fmt.Printf("failed to fetch token: %v", err)
		os.Exit(1)
	}

	fmt.Printf("token: %+v", response)
}

Documentation

Index

Examples

Constants

View Source
const (
	RegisterProductionURL                  = "https://vfd.tra.go.tz/api/vfdRegReq"
	FetchTokenProductionURL                = "https://vfd.tra.go.tz/vfdtoken" //nolint:gosec
	SubmitReceiptProductionURL             = "https://vfd.tra.go.tz/api/efdmsRctInfo"
	SubmitReportProductionURL              = "https://vfd.tra.go.tz/api/efdmszreport"
	VerifyReceiptProductionURL             = "https://verify.tra.go.tz/"
	RegisterTestingURL                     = "https://virtual.tra.go.tz/efdmsRctApi/api/vfdRegReq"
	FetchTokenTestingURL                   = "https://virtual.tra.go.tz/efdmsRctApi/vfdtoken" //nolint:gosec
	SubmitReceiptTestingURL                = "https://virtual.tra.go.tz/efdmsRctApi/api/efdmsRctInfo"
	SubmitReportTestingURL                 = "https://virtual.tra.go.tz/efdmsRctApi/api/efdmszreport"
	VerifyReceiptTestingURL                = "https://virtual.tra.go.tz/efdmsRctVerify/"
	RegisterClientAction       Action      = "register"
	FetchTokenAction           Action      = "token"
	SubmitReceiptAction        Action      = "receipt"
	SubmitReportAction         Action      = "report"
	ReceiptVerificationAction  Action      = "verification"
	CashPaymentType            PaymentType = "CASH"
	CreditCardPaymentType      PaymentType = "CCARD"
	ChequePaymentType          PaymentType = "CHEQUE"
	InvoicePaymentType         PaymentType = "INVOICE"
	ElectronicPaymentType      PaymentType = "EMONEY"
	TINCustomerID              CustomerID  = 1
	LicenceCustomerID          CustomerID  = 2
	VoterIDCustomerID          CustomerID  = 3
	PassportCustomerID         CustomerID  = 4
	NIDACustomerID             CustomerID  = 5
	NonCustomerID              CustomerID  = 6
	MeterNumberCustomerID      CustomerID  = 7
	SubmitReceiptRoutingKey    string      = "vfdrct"
	SubmitReportRoutingKey     string      = "vfdzreport"
	ContentTypeXML             string      = "application/xml"
	RegistrationRequestClient  string      = "webapi"
)

Variables

View Source
var ErrFetchToken = errors.New("fetch token failed")

ErrFetchToken is the error returned when the token request fails. It is a wrapper for the underlying error.

View Source
var ErrReceiptUploadFailed = errors.New("receipt upload failed")
View Source
var ErrRegistrationFailed = errors.New("registration failed")
View Source
var ErrReportSubmitFailed = fmt.Errorf("report submit failed")

Functions

func IsNetworkError

func IsNetworkError(err error) bool

IsNetworkError returns true if the error is a NetworkError.

Example
err := &errors.NetworkError{
	Err:     fmt.Errorf("failed to connect to server"),
	Message: "failed to connect to server",
}

fmt.Println(IsNetworkError(err))
Output:
true

func IsSuccessResponse

func IsSuccessResponse(code int64) bool

IsSuccessResponse checks the response ack code and return true if the code means success and false if otherwise.

func ReceiptBytes

func ReceiptBytes(privateKey *rsa.PrivateKey, params ReceiptParams, customer Customer,
	items []Item, payments []Payment,
) ([]byte, error)
func ReceiptLink(e env.Env, receiptCode string, gc int64, receiptTime string) string

ReceiptLink creates a link to the receipt it accepts RECEIPTCODE, GC and the RECEIPTTIME and env.Env to know if the receipt was created during testing or production.

func ReportBytes

func ReportBytes(privateKey *rsa.PrivateKey, params *ReportParams, address Address,
	vats []VATTOTAL, payments []Payment,
	totals ReportTotals,
) ([]byte, error)

ReportBytes returns the bytes of the report payload. It calls xml.Marshal on the report. then replace all the occurrences of <PAYMENT>, </PAYMENT>, <VATTOTAL>, </VATTOTAL> with empty string "" and then add the xml.Header to the beginning of the payload.

func RequestURL

func RequestURL(e env.Env, action Action) string

RequestURL returns the URL for the specified Action and specified env.Env returns empty string if either action or env is not recognized.

Types

type Action

type Action string

Action signifies the action to be performed among the four defined actions which are INSTANCE registration, token fetching, submission of receipt and submission of report.

type Address

type Address struct {
	Name    string
	Street  string
	Mobile  string
	City    string
	Country string
}

func (*Address) AsList

func (lines *Address) AsList() []string

type Client

type Client struct {
	// contains filtered or unexported fields
}

func NewClient

func NewClient(options ...Option) *Client

func (*Client) FetchToken

func (c *Client) FetchToken(ctx context.Context, url string,
	request *TokenRequest,
) (*TokenResponse, error)

func (*Client) FetchTokenWithMw

func (c *Client) FetchTokenWithMw(ctx context.Context, url string,
	request *TokenRequest, callback OnTokenResponse,
) (*TokenResponse, error)

func (*Client) Register

func (c *Client) Register(ctx context.Context,
	url string, privateKey *rsa.PrivateKey,
	request *RegistrationRequest,
) (*RegistrationResponse, error)

func (*Client) SetHTTPClient

func (c *Client) SetHTTPClient(http *http.Client)

SetHttpClient sets the http client.

func (*Client) SubmitReceipt

func (c *Client) SubmitReceipt(
	ctx context.Context,
	url string,
	headers *RequestHeaders,
	privateKey *rsa.PrivateKey,
	receipt *ReceiptRequest,
) (*Response, error)

func (*Client) SubmitReport

func (c *Client) SubmitReport(
	ctx context.Context,
	url string,
	headers *RequestHeaders,
	privateKey *rsa.PrivateKey,
	report *ReportRequest,
) (*Response, error)

type Customer

type Customer struct {
	Type   CustomerID
	ID     string
	Name   string
	Mobile string
}

Customer contains customer information.

type CustomerID

type CustomerID int

CustomerID is the type of ID the customer used during purchase The Type of ID is to be included in the receipt. Allowed values for CustomerID are 1 through 7. The number to type mapping are as follows: 1: Tax Identification Number (TIN), 2: Driving License, 3: Voters Number, 4: Travel Passport, 5: National ID, 6: NIL (No Identity Used), 7: Meter Number

type FetchTokenFunc

type FetchTokenFunc func(ctx context.Context, url string, request *TokenRequest) (*TokenResponse, error)

FetchTokenFunc is a function that fetches a token from the VFD server.

type Item

type Item struct {
	ID          string
	Description string
	TaxCode     int64
	Quantity    float64
	UnitPrice   float64
	Discount    float64
}

Item represent a purchased item. TaxCode is an integer that can take the value of 1 for taxable items and 3 for non-taxable items. Discount is for the whole package not a unit discount.

type ItemProcessResponse

type ItemProcessResponse struct {
	ITEMS     []*models.ITEM
	VATTOTALS []*models.VATTOTAL
	TOTALS    models.TOTALS
}

func ProcessItems

func ProcessItems(items []Item) *ItemProcessResponse

ProcessItems processes the []Items in the submitted receipt request and create []*models.ITEM which is used to create the xml request also calculates the total discount, total tax exclusive and total tax inclusive.

type OnTokenResponse

type OnTokenResponse func(context.Context, *TokenResponse) error

OnTokenResponse is a callback function that is called when a token is received.

func WrapTokenResponseMiddleware

func WrapTokenResponseMiddleware(next OnTokenResponse, middlewares ...TokenResponseMiddleware) OnTokenResponse

WrapTokenResponseMiddleware wraps a TokenResponseMiddleware with a OnTokenResponse.

type Option

type Option func(*Client)

func WithHttpClient

func WithHttpClient(http *http.Client) Option

type Payment

type Payment struct {
	Type   PaymentType
	Amount float64
}

type PaymentType

type PaymentType string

PaymentType represent the type of payment that is recognized by the VFD server There are five types of payments: CASH, CHEQUE, CCARD, EMONEY and INVOICE.

func ParsePayment

func ParsePayment(value any) PaymentType

ParsePayment ...

type ReceiptParams

type ReceiptParams struct {
	Date           string
	Time           string
	TIN            string
	RegistrationID string
	EFDSerial      string
	ReceiptNum     string
	DailyCounter   int64
	GlobalCounter  int64
	ZNum           string
	ReceiptVNum    string
}

ReceiptParams contains parameters icluded while sending the receipts.

type ReceiptRequest

type ReceiptRequest struct {
	Params   ReceiptParams
	Customer Customer
	Items    []Item
	Payments []Payment
}

type RegistrationRequest

type RegistrationRequest struct {
	ContentType string
	CertSerial  string
	Tin         string
	CertKey     string
}

type RegistrationResponse

type RegistrationResponse struct {
	ACKCODE     string   `xml:"ACKCODE"`
	ACKMSG      string   `xml:"ACKMSG"`
	REGID       string   `xml:"REGID"`
	SERIAL      string   `xml:"SERIAL"`
	UIN         string   `xml:"UIN"`
	TIN         string   `xml:"TIN"`
	VRN         string   `xml:"VRN"`
	MOBILE      string   `xml:"MOBILE"`
	ADDRESS     string   `xml:"ADDRESS"`
	STREET      string   `xml:"STREET"`
	CITY        string   `xml:"CITY"`
	COUNTRY     string   `xml:"COUNTRY"`
	NAME        string   `xml:"NAME"`
	RECEIPTCODE string   `xml:"RECEIPTCODE"`
	REGION      string   `xml:"REGION"`
	ROUTINGKEY  string   `xml:"ROUTINGKEY"`
	GC          int64    `xml:"GC"`
	TAXOFFICE   string   `xml:"TAXOFFICE"`
	USERNAME    string   `xml:"USERNAME"`
	PASSWORD    string   `xml:"PASSWORD"`
	TOKENPATH   string   `xml:"TOKENPATH"`
	TAXCODES    TAXCODES `xml:"TAXCODES"`
}

func Register

func Register(ctx context.Context, requestURL string, privateKey *rsa.PrivateKey,
	request *RegistrationRequest,
) (*RegistrationResponse, error)

Register send the registration for a Virtual Fiscal Device to the VFD server. The registration request is signed with the private key of the certificate used to authenticate the client. The registration request can be sent to the VFD server multiple times. The server will return the same registration response. Only the GC (Global Counter) will be incremented.

type ReportParams

type ReportParams struct {
	Date             string
	Time             string
	VRN              string
	TIN              string
	UIN              string
	TaxOffice        string
	RegistrationID   string
	ZNumber          string
	EFDSerial        string
	RegistrationDate string
}

type ReportRequest

type ReportRequest struct {
	Params  *ReportParams
	Address *Address
	Totals  *ReportTotals
	VATS    []VATTOTAL
	Payment []Payment
}

type ReportTotals

type ReportTotals struct {
	DailyTotalAmount float64
	Gross            float64
	Corrections      float64
	Discounts        float64
	Surcharges       float64
	TicketsVoid      int64
	TicketsVoidTotal float64
	TicketsFiscal    int64
	TicketsNonFiscal int64
}

ReportTotals contains different number of totals.

type RequestHeaders

type RequestHeaders struct {
	CertSerial  string
	BearerToken string
}

RequestHeaders represent collection of request headers during receipt or Z report sending via VFD Service.

type Response

type Response struct {
	Number  int64  `json:"number,omitempty"`
	Date    string `json:"date,omitempty"`
	Time    string `json:"time,omitempty"`
	Code    int64  `json:"code,omitempty"`
	Message string `json:"message,omitempty"`
}

Response contains details returned when submitting a receipt to the VFD Service or a Z report. Number (int) is the receipt number in case of a receipt submission and the Z report number in case of a Z report submission. Date (string) is the date of the receipt or Z report submission. The format is YYYY-MM-DD. Time (string) is the time of the receipt or Z report submission. The format is HH24:MI:SS Code (int) is the response code. 0 means success. Message (string) is the response message.

func SubmitReceipt

func SubmitReceipt(ctx context.Context, requestURL string, headers *RequestHeaders, privateKey *rsa.PrivateKey,
	receiptRequest *ReceiptRequest,
) (*Response, error)

SubmitReceipt uploads a receipt to the VFD server.

func SubmitReport

func SubmitReport(ctx context.Context, url string, headers *RequestHeaders, privateKey *rsa.PrivateKey,
	report *ReportRequest,
) (*Response, error)

type Service

type Service interface {
	// Register is used to register a virtual fiscal device (VFD) with the VFD Service.
	// If successful, the VFD Service returns a registration response containing the
	// VFD details and the credentials to use when submitting receipts and Z reports.
	// Registering a VFD is a one-time operation. The subsequent calls to Register will
	// yield the same response.VFD should store the registration response to
	// avoid calling Register again.
	Register(ctx context.Context, url string, privateKey *rsa.PrivateKey, request *RegistrationRequest,
	) (*RegistrationResponse, error)

	// FetchToken is used to fetch a token from the VFD Service. The token is used
	// to authenticate the VFD when submitting receipts and Z reports.
	// credentials used here are the ones returned by the Register method.
	FetchToken(ctx context.Context, url string, request *TokenRequest) (*TokenResponse, error)

	// SubmitReceipt is used to submit a receipt to the VFD Service. The receipt
	// is signed using the private key. The private key is obtained from the certificate
	// issued by the Revenue Authority during integration.
	SubmitReceipt(
		ctx context.Context, url string, headers *RequestHeaders,
		privateKey *rsa.PrivateKey, receipt *ReceiptRequest) (*Response, error)

	// SubmitReport is used to submit a Z report to the VFD Service. The Z report
	// is signed using the private key. The private key is obtained from the certificate
	// issued by the Revenue Authority during integration.
	SubmitReport(
		ctx context.Context, url string, headers *RequestHeaders,
		privateKey *rsa.PrivateKey, report *ReportRequest) (*Response, error)
}

type TAXCODES

type TAXCODES struct {
	XMLName xml.Name `xml:"TAXCODES"`
	Text    string   `xml:",chardata"`
	CODEA   string   `xml:"CODEA"`
	CODEB   string   `xml:"CODEB"`
	CODEC   string   `xml:"CODEC"`
	CODED   string   `xml:"CODED"`
}

type TokenRequest

type TokenRequest struct {
	Username  string
	Password  string
	GrantType string
}

TokenRequest contains the request parameters needed to get a token. GrantType - The type of the grant_type. Username - The username of the user. Password - The password of the user.

type TokenResponse

type TokenResponse struct {
	Code        string `json:"code,omitempty"`
	Message     string `json:"message,omitempty"`
	AccessToken string `json:"access_token,omitempty"`
	TokenType   string `json:"token_type,omitempty"`
	ExpiresIn   int64  `json:"expires_in,omitempty"`
	Error       string `json:"error,omitempty"`
}

TokenResponse contains the response parameters returned by the token endpoint.

func FetchToken

func FetchToken(ctx context.Context, url string, request *TokenRequest) (*TokenResponse, error)

FetchToken retrieves a token from the VFD server. If the status code is not 200, an error is returned. Error Message will contain TokenResponse.Code and TokenResponse.Message FetchToken wraps internally a *http.Client responsible for making http calls. It has a timeout of 70 seconds. It is advised to call this only when the previous token has expired. It will still work if called before the token expires.

func FetchTokenWithMw

func FetchTokenWithMw(ctx context.Context, url string,
	request *TokenRequest, callback OnTokenResponse) (*TokenResponse, error)

FetchTokenWithMw retrieves a token from the VFD server then passes it to the callback function This is because the response might have a code and message that needs to be handled.

func (*TokenResponse) String

func (tr *TokenResponse) String() string

type TokenResponseMiddleware

type TokenResponseMiddleware func(next OnTokenResponse) OnTokenResponse

TokenResponseMiddleware is a middleware function that is called when a token is received.

type URL

type URL struct {
	Registration  string
	FetchToken    string
	SubmitReceipt string
	SubmitReport  string
	VerifyReceipt string
}

URL is a struct that holds the URLs for the four actions.

type VATTOTAL

type VATTOTAL struct {
	ID        string
	Rate      float64
	TaxAmount float64
	NetAmount float64
}

VATTOTAL represent the VAT details.

Directories

Path Synopsis
internal
Package mock is a generated GoMock package.
Package mock is a generated GoMock package.
pkg
env
vat

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL