master
Serge Bazanski 2018-11-12 12:21:11 +01:00
parent 54a97389ca
commit 6269824571
7 changed files with 1357 additions and 81 deletions

11
a_main-packr.go Normal file

File diff suppressed because one or more lines are too long

View File

@ -6,16 +6,31 @@ message Item {
string title = 1;
uint64 count = 2;
uint64 unit_price = 3;
// in thousands of percent points
// (ie 23% == 23000)
uint64 vat = 4;
}
message CreateInvoiceRequest {
message ContactPoint {
string medium = 1;
string contact = 2;
}
message Invoice {
repeated Item item = 1;
repeated string invoicer_biling = 2;
repeated string customer_billing = 3;
string invoicer_vat_id = 4;
string customer_vat_id = 5;
bool reverse_vat = 6;
repeated string invoicer_billing = 2;
repeated ContactPoint invoicer_contact = 3;
repeated string customer_billing = 4;
string invoicer_vat_id = 5;
string customer_vat_id = 6;
bool reverse_vat = 7;
int64 days_due = 8;
string iban = 9;
string swift = 10;
}
message CreateInvoiceRequest {
Invoice invoice = 1;
}
message CreateInvoiceResponse {
@ -23,6 +38,39 @@ message CreateInvoiceResponse {
string uid = 1;
}
message GetInvoiceRequest {
string uid = 1;
}
message GetInvoiceResponse {
Invoice invoice = 1;
enum State {
STATE_INVALID = 0;
STATE_PROFORMA = 1;
STATE_SEALED = 2;
};
State state = 2;
string final_uid = 3;
}
message RenderInvoiceRequest {
string uid = 1;
}
message RenderInvoiceResponse {
bytes data = 1;
}
message SealInvoiceRequest {
string uid = 1;
}
message SealInvoiceResponse {
}
service Inboice {
rpc CreateInvoice(CreateInvoiceRequest) returns (CreateInvoiceResponse);
rpc GetInvoice(GetInvoiceRequest) returns (GetInvoiceResponse);
rpc RenderInvoice(RenderInvoiceRequest) returns (stream RenderInvoiceResponse);
rpc SealInvoice(SealInvoiceRequest) returns (SealInvoiceResponse);
}

167
main.go
View File

@ -17,28 +17,185 @@ import (
var (
flagListenAddress string
flagInit bool
)
type service struct {
m *model
}
func (s *service) CreateInvoice(ctx context.Context, req *pb.CreateInvoiceRequest) (*pb.CreateInvoiceResponse, error) {
return nil, status.Error(codes.Unimplemented, "unimplemented")
if req.Invoice == nil {
return nil, status.Error(codes.InvalidArgument, "invoice must be given")
}
if len(req.Invoice.Item) < 1 {
return nil, status.Error(codes.InvalidArgument, "invoice must contain at least one item")
}
for i, item := range req.Invoice.Item {
if item.Title == "" {
return nil, status.Errorf(codes.InvalidArgument, "invoice item %d must have title set", i)
}
if item.Count == 0 || item.Count > 1000000 {
return nil, status.Errorf(codes.InvalidArgument, "invoice item %d must have correct count", i)
}
if item.UnitPrice == 0 {
return nil, status.Errorf(codes.InvalidArgument, "invoice item %d must have correct unit price", i)
}
if item.Vat > 100000 {
return nil, status.Errorf(codes.InvalidArgument, "invoice item %d must have correct vat set", i)
}
}
if len(req.Invoice.CustomerBilling) < 1 {
return nil, status.Error(codes.InvalidArgument, "invoice must contain at least one line of the customer's billing address")
}
if len(req.Invoice.InvoicerBilling) < 1 {
return nil, status.Error(codes.InvalidArgument, "invoice must contain at least one line of the invoicer's billing address")
}
for i, c := range req.Invoice.InvoicerContact {
if c.Medium == "" {
return nil, status.Errorf(codes.InvalidArgument, "contact point %d must have medium set", i)
}
if c.Contact == "" {
return nil, status.Errorf(codes.InvalidArgument, "contact point %d must have contact set", i)
}
}
if req.Invoice.InvoicerVatId == "" {
return nil, status.Error(codes.InvalidArgument, "invoice must contain invoicer's vat id")
}
uid, err := s.m.createInvoice(ctx, req.Invoice)
if err != nil {
if _, ok := status.FromError(err); ok {
return nil, err
}
glog.Errorf("createInvoice(_, _): %v", err)
return nil, status.Error(codes.Unavailable, "could not create invoice")
}
return &pb.CreateInvoiceResponse{
Uid: uid,
}, nil
}
func newService() *service {
return &service{}
func (s *service) GetInvoice(ctx context.Context, req *pb.GetInvoiceRequest) (*pb.GetInvoiceResponse, error) {
invoice, err := s.m.getInvoice(ctx, req.Uid)
if err != nil {
if _, ok := status.FromError(err); ok {
return nil, err
}
glog.Errorf("getInvoice(_, %q): %v", req.Uid, err)
return nil, status.Error(codes.Unavailable, "internal server error")
}
sealedUid, err := s.m.getSealedUid(ctx, req.Uid)
if err != nil {
if _, ok := status.FromError(err); ok {
return nil, err
}
glog.Errorf("getSealedUid(_, %q): %v", req.Uid, err)
return nil, status.Error(codes.Unavailable, "internal server error")
}
res := &pb.GetInvoiceResponse{
Invoice: invoice,
}
if sealedUid == "" {
res.State = pb.GetInvoiceResponse_STATE_PROFORMA
} else {
res.State = pb.GetInvoiceResponse_STATE_SEALED
res.FinalUid = sealedUid
}
return res, nil
}
func newService(m *model) *service {
return &service{
m: m,
}
}
func (s *service) RenderInvoice(req *pb.RenderInvoiceRequest, srv pb.Inboice_RenderInvoiceServer) error {
sealed, err := s.m.getSealedUid(srv.Context(), req.Uid)
if err != nil {
if _, ok := status.FromError(err); ok {
return err
}
glog.Errorf("getSealedUid(_, %q): %v", req.Uid, err)
return status.Error(codes.Unavailable, "internal server error")
}
var rendered []byte
if sealed != "" {
// Invoice is sealed, return stored PDF.
rendered, err = s.m.getRendered(srv.Context(), req.Uid)
if err != nil {
if _, ok := status.FromError(err); ok {
return err
}
glog.Errorf("getRendered(_, %q): %v", req.Uid, err)
return status.Error(codes.Unavailable, "internal server error")
}
} else {
// Invoice is proforma, render.
invoice, err := s.m.getInvoice(srv.Context(), req.Uid)
if err != nil {
if _, ok := status.FromError(err); ok {
return err
}
glog.Errorf("getInvoice(_, %q): %v", req.Uid, err)
return status.Error(codes.Unavailable, "internal server error")
}
rendered, err = renderInvoicePDF(invoice, "xxxx", true)
if err != nil {
glog.Errorf("renderProformaPDF(_): %v", err)
return status.Error(codes.Unavailable, "internal server error")
}
}
chunkSize := 16 * 1024
chunk := &pb.RenderInvoiceResponse{}
for i := 0; i < len(rendered); i += chunkSize {
if i+chunkSize > len(rendered) {
chunk.Data = rendered[i:len(rendered)]
} else {
chunk.Data = rendered[i : i+chunkSize]
}
if err := srv.Send(chunk); err != nil {
glog.Errorf("srv.Send: %v", err)
return status.Error(codes.Unavailable, "stream broken")
}
}
return nil
}
func (s *service) SealInvoice(ctx context.Context, req *pb.SealInvoiceRequest) (*pb.SealInvoiceResponse, error) {
if err := s.m.sealInvoice(ctx, req.Uid); err != nil {
if _, ok := status.FromError(err); ok {
return nil, err
}
glog.Errorf("sealInvoice(_, %q): %v", req.Uid, err)
return nil, status.Error(codes.Unavailable, "internal server error")
}
return &pb.SealInvoiceResponse{}, nil
}
func init() {
flag.Set("logstostderr", "true")
flag.Set("logtostderr", "true")
}
func main() {
flag.StringVar(&flagListenAddress, "listen_address", "127.0.0.1:42000", "gRPC listen address")
flag.BoolVar(&flagInit, "init_db", false, "init database and exit")
flag.Parse()
s := newService()
m, err := newModel("./foo.db")
if err != nil {
glog.Exitf("newModel: %v", err)
}
if flagInit {
glog.Exit(m.init())
}
s := newService(m)
grpc.EnableTracing = true
grpcLis, err := net.Listen("tcp", flagListenAddress)

213
model.go Normal file
View File

@ -0,0 +1,213 @@
package main
import (
"context"
"database/sql"
"fmt"
"strconv"
"github.com/golang/glog"
"github.com/golang/protobuf/proto"
_ "github.com/mattn/go-sqlite3"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
pb "code.hackerspace.pl/q3k/inboice/proto"
)
type model struct {
db *sql.DB
}
func newModel(dsn string) (*model, error) {
db, err := sql.Open("sqlite3", dsn)
if err != nil {
return nil, err
}
return &model{
db: db,
}, nil
}
func (m *model) init() error {
_, err := m.db.Exec(`
create table invoice (
id integer primary key not null,
proto blob not null
);
create table invoice_seal (
id integer primary key not null,
invoice_id integer not null,
final_uid text not null unique,
foreign key (invoice_id) references invoice(id)
);
create table invoice_blob (
id integer primary key not null,
invoice_id integer not null,
pdf blob not null,
foreign key (invoice_id) references invoice(id)
);
`)
return err
}
func (m *model) sealInvoice(ctx context.Context, uid string) error {
id, err := strconv.Atoi(uid)
if err != nil {
return status.Error(codes.InvalidArgument, "invalid uid")
}
invoice, err := m.getInvoice(ctx, uid)
if err != nil {
return err
}
tx, err := m.db.BeginTx(ctx, nil)
if err != nil {
return err
}
q := `
insert into invoice_seal (
invoice_id, final_uid
) values (
?,
( select printf("%04d", ifnull( (select final_uid as v from invoice_seal order by final_uid desc limit 1), 7) + 1 ))
)
`
res, err := tx.Exec(q, id)
if err != nil {
return err
}
lastInvoiceSealId, err := res.LastInsertId()
if err != nil {
return err
}
q = `
select final_uid from invoice_seal where id = ?
`
var finalUid string
if err := tx.QueryRow(q, lastInvoiceSealId).Scan(&finalUid); err != nil {
return err
}
q = `
insert into invoice_blob (
invoice_id, pdf
) values (
?,
?
)
`
pdfBlob, err := renderInvoicePDF(invoice, finalUid, false)
if err != nil {
return err
}
if _, err := tx.Exec(q, id, pdfBlob); err != nil {
return err
}
if err := tx.Commit(); err != nil {
return err
}
return nil
}
func (m *model) createInvoice(ctx context.Context, i *pb.Invoice) (string, error) {
data, err := proto.Marshal(i)
if err != nil {
return "", err
}
sql := `
insert into invoice (
proto
) values (
?
)
`
res, err := m.db.Exec(sql, data)
if err != nil {
return "", err
}
id, err := res.LastInsertId()
if err != nil {
return "", err
}
glog.Infof("%+v", id)
return fmt.Sprintf("%d", id), nil
}
func (m *model) getRendered(ctx context.Context, uid string) ([]byte, error) {
id, err := strconv.Atoi(uid)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "invalid uid")
}
q := `
select invoice_blob.pdf from invoice_blob where invoice_blob.invoice_id = ?
`
res := m.db.QueryRow(q, id)
data := []byte{}
if err := res.Scan(&data); err != nil {
if err == sql.ErrNoRows {
return nil, status.Error(codes.InvalidArgument, "no such invoice")
}
return nil, err
}
return data, nil
}
func (m *model) getSealedUid(ctx context.Context, uid string) (string, error) {
id, err := strconv.Atoi(uid)
if err != nil {
return "", status.Error(codes.InvalidArgument, "invalid uid")
}
q := `
select invoice_seal.final_uid from invoice_seal where invoice_seal.invoice_id = ?
`
res := m.db.QueryRow(q, id)
finalUid := ""
if err := res.Scan(&finalUid); err != nil {
if err == sql.ErrNoRows {
return "", nil
}
return "", err
}
return finalUid, nil
}
func (m *model) getInvoice(ctx context.Context, uid string) (*pb.Invoice, error) {
id, err := strconv.Atoi(uid)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "invalid uid")
}
q := `
select invoice.proto from invoice where invoice.id = ?
`
res := m.db.QueryRow(q, id)
data := []byte{}
if err := res.Scan(&data); err != nil {
if err == sql.ErrNoRows {
return nil, status.Error(codes.NotFound, "no such invoice")
}
return nil, err
}
p := &pb.Invoice{}
if err := proto.Unmarshal(data, p); err != nil {
return nil, err
}
return p, nil
}

View File

@ -22,10 +22,40 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type GetInvoiceResponse_State int32
const (
GetInvoiceResponse_STATE_INVALID GetInvoiceResponse_State = 0
GetInvoiceResponse_STATE_PROFORMA GetInvoiceResponse_State = 1
GetInvoiceResponse_STATE_SEALED GetInvoiceResponse_State = 2
)
var GetInvoiceResponse_State_name = map[int32]string{
0: "STATE_INVALID",
1: "STATE_PROFORMA",
2: "STATE_SEALED",
}
var GetInvoiceResponse_State_value = map[string]int32{
"STATE_INVALID": 0,
"STATE_PROFORMA": 1,
"STATE_SEALED": 2,
}
func (x GetInvoiceResponse_State) String() string {
return proto.EnumName(GetInvoiceResponse_State_name, int32(x))
}
func (GetInvoiceResponse_State) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{6, 0}
}
type Item struct {
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
Count uint64 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"`
UnitPrice uint64 `protobuf:"varint,3,opt,name=unit_price,json=unitPrice,proto3" json:"unit_price,omitempty"`
Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
Count uint64 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"`
UnitPrice uint64 `protobuf:"varint,3,opt,name=unit_price,json=unitPrice,proto3" json:"unit_price,omitempty"`
// in thousands of percent points
// (ie 23% == 23000)
Vat uint64 `protobuf:"varint,4,opt,name=vat,proto3" json:"vat,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@ -85,13 +115,166 @@ func (m *Item) GetVat() uint64 {
return 0
}
type ContactPoint struct {
Medium string `protobuf:"bytes,1,opt,name=medium,proto3" json:"medium,omitempty"`
Contact string `protobuf:"bytes,2,opt,name=contact,proto3" json:"contact,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ContactPoint) Reset() { *m = ContactPoint{} }
func (m *ContactPoint) String() string { return proto.CompactTextString(m) }
func (*ContactPoint) ProtoMessage() {}
func (*ContactPoint) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{1}
}
func (m *ContactPoint) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ContactPoint.Unmarshal(m, b)
}
func (m *ContactPoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ContactPoint.Marshal(b, m, deterministic)
}
func (m *ContactPoint) XXX_Merge(src proto.Message) {
xxx_messageInfo_ContactPoint.Merge(m, src)
}
func (m *ContactPoint) XXX_Size() int {
return xxx_messageInfo_ContactPoint.Size(m)
}
func (m *ContactPoint) XXX_DiscardUnknown() {
xxx_messageInfo_ContactPoint.DiscardUnknown(m)
}
var xxx_messageInfo_ContactPoint proto.InternalMessageInfo
func (m *ContactPoint) GetMedium() string {
if m != nil {
return m.Medium
}
return ""
}
func (m *ContactPoint) GetContact() string {
if m != nil {
return m.Contact
}
return ""
}
type Invoice struct {
Item []*Item `protobuf:"bytes,1,rep,name=item,proto3" json:"item,omitempty"`
InvoicerBilling []string `protobuf:"bytes,2,rep,name=invoicer_billing,json=invoicerBilling,proto3" json:"invoicer_billing,omitempty"`
InvoicerContact []*ContactPoint `protobuf:"bytes,3,rep,name=invoicer_contact,json=invoicerContact,proto3" json:"invoicer_contact,omitempty"`
CustomerBilling []string `protobuf:"bytes,4,rep,name=customer_billing,json=customerBilling,proto3" json:"customer_billing,omitempty"`
InvoicerVatId string `protobuf:"bytes,5,opt,name=invoicer_vat_id,json=invoicerVatId,proto3" json:"invoicer_vat_id,omitempty"`
CustomerVatId string `protobuf:"bytes,6,opt,name=customer_vat_id,json=customerVatId,proto3" json:"customer_vat_id,omitempty"`
ReverseVat bool `protobuf:"varint,7,opt,name=reverse_vat,json=reverseVat,proto3" json:"reverse_vat,omitempty"`
DaysDue int64 `protobuf:"varint,8,opt,name=days_due,json=daysDue,proto3" json:"days_due,omitempty"`
Iban string `protobuf:"bytes,9,opt,name=iban,proto3" json:"iban,omitempty"`
Swift string `protobuf:"bytes,10,opt,name=swift,proto3" json:"swift,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Invoice) Reset() { *m = Invoice{} }
func (m *Invoice) String() string { return proto.CompactTextString(m) }
func (*Invoice) ProtoMessage() {}
func (*Invoice) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{2}
}
func (m *Invoice) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Invoice.Unmarshal(m, b)
}
func (m *Invoice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Invoice.Marshal(b, m, deterministic)
}
func (m *Invoice) XXX_Merge(src proto.Message) {
xxx_messageInfo_Invoice.Merge(m, src)
}
func (m *Invoice) XXX_Size() int {
return xxx_messageInfo_Invoice.Size(m)
}
func (m *Invoice) XXX_DiscardUnknown() {
xxx_messageInfo_Invoice.DiscardUnknown(m)
}
var xxx_messageInfo_Invoice proto.InternalMessageInfo
func (m *Invoice) GetItem() []*Item {
if m != nil {
return m.Item
}
return nil
}
func (m *Invoice) GetInvoicerBilling() []string {
if m != nil {
return m.InvoicerBilling
}
return nil
}
func (m *Invoice) GetInvoicerContact() []*ContactPoint {
if m != nil {
return m.InvoicerContact
}
return nil
}
func (m *Invoice) GetCustomerBilling() []string {
if m != nil {
return m.CustomerBilling
}
return nil
}
func (m *Invoice) GetInvoicerVatId() string {
if m != nil {
return m.InvoicerVatId
}
return ""
}
func (m *Invoice) GetCustomerVatId() string {
if m != nil {
return m.CustomerVatId
}
return ""
}
func (m *Invoice) GetReverseVat() bool {
if m != nil {
return m.ReverseVat
}
return false
}
func (m *Invoice) GetDaysDue() int64 {
if m != nil {
return m.DaysDue
}
return 0
}
func (m *Invoice) GetIban() string {
if m != nil {
return m.Iban
}
return ""
}
func (m *Invoice) GetSwift() string {
if m != nil {
return m.Swift
}
return ""
}
type CreateInvoiceRequest struct {
Item []*Item `protobuf:"bytes,1,rep,name=item,proto3" json:"item,omitempty"`
InvoicerBiling []string `protobuf:"bytes,2,rep,name=invoicer_biling,json=invoicerBiling,proto3" json:"invoicer_biling,omitempty"`
CustomerBilling []string `protobuf:"bytes,3,rep,name=customer_billing,json=customerBilling,proto3" json:"customer_billing,omitempty"`
InvoicerVatId string `protobuf:"bytes,4,opt,name=invoicer_vat_id,json=invoicerVatId,proto3" json:"invoicer_vat_id,omitempty"`
CustomerVatId string `protobuf:"bytes,5,opt,name=customer_vat_id,json=customerVatId,proto3" json:"customer_vat_id,omitempty"`
ReverseVat bool `protobuf:"varint,6,opt,name=reverse_vat,json=reverseVat,proto3" json:"reverse_vat,omitempty"`
Invoice *Invoice `protobuf:"bytes,1,opt,name=invoice,proto3" json:"invoice,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -101,7 +284,7 @@ func (m *CreateInvoiceRequest) Reset() { *m = CreateInvoiceRequest{} }
func (m *CreateInvoiceRequest) String() string { return proto.CompactTextString(m) }
func (*CreateInvoiceRequest) ProtoMessage() {}
func (*CreateInvoiceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{1}
return fileDescriptor_aca47770af3442cd, []int{3}
}
func (m *CreateInvoiceRequest) XXX_Unmarshal(b []byte) error {
@ -122,48 +305,13 @@ func (m *CreateInvoiceRequest) XXX_DiscardUnknown() {
var xxx_messageInfo_CreateInvoiceRequest proto.InternalMessageInfo
func (m *CreateInvoiceRequest) GetItem() []*Item {
func (m *CreateInvoiceRequest) GetInvoice() *Invoice {
if m != nil {
return m.Item
return m.Invoice
}
return nil
}
func (m *CreateInvoiceRequest) GetInvoicerBiling() []string {
if m != nil {
return m.InvoicerBiling
}
return nil
}
func (m *CreateInvoiceRequest) GetCustomerBilling() []string {
if m != nil {
return m.CustomerBilling
}
return nil
}
func (m *CreateInvoiceRequest) GetInvoicerVatId() string {
if m != nil {
return m.InvoicerVatId
}
return ""
}
func (m *CreateInvoiceRequest) GetCustomerVatId() string {
if m != nil {
return m.CustomerVatId
}
return ""
}
func (m *CreateInvoiceRequest) GetReverseVat() bool {
if m != nil {
return m.ReverseVat
}
return false
}
type CreateInvoiceResponse struct {
// Unique invoice ID
Uid string `protobuf:"bytes,1,opt,name=uid,proto3" json:"uid,omitempty"`
@ -176,7 +324,7 @@ func (m *CreateInvoiceResponse) Reset() { *m = CreateInvoiceResponse{} }
func (m *CreateInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*CreateInvoiceResponse) ProtoMessage() {}
func (*CreateInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{2}
return fileDescriptor_aca47770af3442cd, []int{4}
}
func (m *CreateInvoiceResponse) XXX_Unmarshal(b []byte) error {
@ -204,36 +352,306 @@ func (m *CreateInvoiceResponse) GetUid() string {
return ""
}
type GetInvoiceRequest struct {
Uid string `protobuf:"bytes,1,opt,name=uid,proto3" json:"uid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetInvoiceRequest) Reset() { *m = GetInvoiceRequest{} }
func (m *GetInvoiceRequest) String() string { return proto.CompactTextString(m) }
func (*GetInvoiceRequest) ProtoMessage() {}
func (*GetInvoiceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{5}
}
func (m *GetInvoiceRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetInvoiceRequest.Unmarshal(m, b)
}
func (m *GetInvoiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetInvoiceRequest.Marshal(b, m, deterministic)
}
func (m *GetInvoiceRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetInvoiceRequest.Merge(m, src)
}
func (m *GetInvoiceRequest) XXX_Size() int {
return xxx_messageInfo_GetInvoiceRequest.Size(m)
}
func (m *GetInvoiceRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GetInvoiceRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GetInvoiceRequest proto.InternalMessageInfo
func (m *GetInvoiceRequest) GetUid() string {
if m != nil {
return m.Uid
}
return ""
}
type GetInvoiceResponse struct {
Invoice *Invoice `protobuf:"bytes,1,opt,name=invoice,proto3" json:"invoice,omitempty"`
State GetInvoiceResponse_State `protobuf:"varint,2,opt,name=state,proto3,enum=proto.GetInvoiceResponse_State" json:"state,omitempty"`
FinalUid string `protobuf:"bytes,3,opt,name=final_uid,json=finalUid,proto3" json:"final_uid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetInvoiceResponse) Reset() { *m = GetInvoiceResponse{} }
func (m *GetInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*GetInvoiceResponse) ProtoMessage() {}
func (*GetInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{6}
}
func (m *GetInvoiceResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetInvoiceResponse.Unmarshal(m, b)
}
func (m *GetInvoiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetInvoiceResponse.Marshal(b, m, deterministic)
}
func (m *GetInvoiceResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetInvoiceResponse.Merge(m, src)
}
func (m *GetInvoiceResponse) XXX_Size() int {
return xxx_messageInfo_GetInvoiceResponse.Size(m)
}
func (m *GetInvoiceResponse) XXX_DiscardUnknown() {
xxx_messageInfo_GetInvoiceResponse.DiscardUnknown(m)
}
var xxx_messageInfo_GetInvoiceResponse proto.InternalMessageInfo
func (m *GetInvoiceResponse) GetInvoice() *Invoice {
if m != nil {
return m.Invoice
}
return nil
}
func (m *GetInvoiceResponse) GetState() GetInvoiceResponse_State {
if m != nil {
return m.State
}
return GetInvoiceResponse_STATE_INVALID
}
func (m *GetInvoiceResponse) GetFinalUid() string {
if m != nil {
return m.FinalUid
}
return ""
}
type RenderInvoiceRequest struct {
Uid string `protobuf:"bytes,1,opt,name=uid,proto3" json:"uid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RenderInvoiceRequest) Reset() { *m = RenderInvoiceRequest{} }
func (m *RenderInvoiceRequest) String() string { return proto.CompactTextString(m) }
func (*RenderInvoiceRequest) ProtoMessage() {}
func (*RenderInvoiceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{7}
}
func (m *RenderInvoiceRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RenderInvoiceRequest.Unmarshal(m, b)
}
func (m *RenderInvoiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RenderInvoiceRequest.Marshal(b, m, deterministic)
}
func (m *RenderInvoiceRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_RenderInvoiceRequest.Merge(m, src)
}
func (m *RenderInvoiceRequest) XXX_Size() int {
return xxx_messageInfo_RenderInvoiceRequest.Size(m)
}
func (m *RenderInvoiceRequest) XXX_DiscardUnknown() {
xxx_messageInfo_RenderInvoiceRequest.DiscardUnknown(m)
}
var xxx_messageInfo_RenderInvoiceRequest proto.InternalMessageInfo
func (m *RenderInvoiceRequest) GetUid() string {
if m != nil {
return m.Uid
}
return ""
}
type RenderInvoiceResponse struct {
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *RenderInvoiceResponse) Reset() { *m = RenderInvoiceResponse{} }
func (m *RenderInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*RenderInvoiceResponse) ProtoMessage() {}
func (*RenderInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{8}
}
func (m *RenderInvoiceResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_RenderInvoiceResponse.Unmarshal(m, b)
}
func (m *RenderInvoiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_RenderInvoiceResponse.Marshal(b, m, deterministic)
}
func (m *RenderInvoiceResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_RenderInvoiceResponse.Merge(m, src)
}
func (m *RenderInvoiceResponse) XXX_Size() int {
return xxx_messageInfo_RenderInvoiceResponse.Size(m)
}
func (m *RenderInvoiceResponse) XXX_DiscardUnknown() {
xxx_messageInfo_RenderInvoiceResponse.DiscardUnknown(m)
}
var xxx_messageInfo_RenderInvoiceResponse proto.InternalMessageInfo
func (m *RenderInvoiceResponse) GetData() []byte {
if m != nil {
return m.Data
}
return nil
}
type SealInvoiceRequest struct {
Uid string `protobuf:"bytes,1,opt,name=uid,proto3" json:"uid,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SealInvoiceRequest) Reset() { *m = SealInvoiceRequest{} }
func (m *SealInvoiceRequest) String() string { return proto.CompactTextString(m) }
func (*SealInvoiceRequest) ProtoMessage() {}
func (*SealInvoiceRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{9}
}
func (m *SealInvoiceRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SealInvoiceRequest.Unmarshal(m, b)
}
func (m *SealInvoiceRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SealInvoiceRequest.Marshal(b, m, deterministic)
}
func (m *SealInvoiceRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_SealInvoiceRequest.Merge(m, src)
}
func (m *SealInvoiceRequest) XXX_Size() int {
return xxx_messageInfo_SealInvoiceRequest.Size(m)
}
func (m *SealInvoiceRequest) XXX_DiscardUnknown() {
xxx_messageInfo_SealInvoiceRequest.DiscardUnknown(m)
}
var xxx_messageInfo_SealInvoiceRequest proto.InternalMessageInfo
func (m *SealInvoiceRequest) GetUid() string {
if m != nil {
return m.Uid
}
return ""
}
type SealInvoiceResponse struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *SealInvoiceResponse) Reset() { *m = SealInvoiceResponse{} }
func (m *SealInvoiceResponse) String() string { return proto.CompactTextString(m) }
func (*SealInvoiceResponse) ProtoMessage() {}
func (*SealInvoiceResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_aca47770af3442cd, []int{10}
}
func (m *SealInvoiceResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SealInvoiceResponse.Unmarshal(m, b)
}
func (m *SealInvoiceResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_SealInvoiceResponse.Marshal(b, m, deterministic)
}
func (m *SealInvoiceResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_SealInvoiceResponse.Merge(m, src)
}
func (m *SealInvoiceResponse) XXX_Size() int {
return xxx_messageInfo_SealInvoiceResponse.Size(m)
}
func (m *SealInvoiceResponse) XXX_DiscardUnknown() {
xxx_messageInfo_SealInvoiceResponse.DiscardUnknown(m)
}
var xxx_messageInfo_SealInvoiceResponse proto.InternalMessageInfo
func init() {
proto.RegisterEnum("proto.GetInvoiceResponse_State", GetInvoiceResponse_State_name, GetInvoiceResponse_State_value)
proto.RegisterType((*Item)(nil), "proto.Item")
proto.RegisterType((*ContactPoint)(nil), "proto.ContactPoint")
proto.RegisterType((*Invoice)(nil), "proto.Invoice")
proto.RegisterType((*CreateInvoiceRequest)(nil), "proto.CreateInvoiceRequest")
proto.RegisterType((*CreateInvoiceResponse)(nil), "proto.CreateInvoiceResponse")
proto.RegisterType((*GetInvoiceRequest)(nil), "proto.GetInvoiceRequest")
proto.RegisterType((*GetInvoiceResponse)(nil), "proto.GetInvoiceResponse")
proto.RegisterType((*RenderInvoiceRequest)(nil), "proto.RenderInvoiceRequest")
proto.RegisterType((*RenderInvoiceResponse)(nil), "proto.RenderInvoiceResponse")
proto.RegisterType((*SealInvoiceRequest)(nil), "proto.SealInvoiceRequest")
proto.RegisterType((*SealInvoiceResponse)(nil), "proto.SealInvoiceResponse")
}
func init() { proto.RegisterFile("inboice.proto", fileDescriptor_aca47770af3442cd) }
var fileDescriptor_aca47770af3442cd = []byte{
// 309 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xbd, 0x6e, 0xf2, 0x30,
0x14, 0x86, 0x65, 0x12, 0xf8, 0xbe, 0x1c, 0x44, 0x41, 0x16, 0x95, 0xac, 0xfe, 0x88, 0x88, 0xa1,
0x0d, 0x0b, 0x03, 0xbd, 0x03, 0x3a, 0xa5, 0x53, 0x65, 0xa9, 0xac, 0x28, 0x84, 0xa3, 0xca, 0x12,
0xd8, 0xa9, 0x73, 0x92, 0xab, 0xef, 0x50, 0xd9, 0x4e, 0xaa, 0xb6, 0x62, 0x8a, 0xfd, 0x9c, 0xc7,
0xce, 0x9b, 0x37, 0x30, 0x51, 0xfa, 0x60, 0x54, 0x89, 0xeb, 0xca, 0x1a, 0x32, 0x7c, 0xe8, 0x1f,
0xcb, 0x12, 0xe2, 0x9c, 0xf0, 0xcc, 0xe7, 0x30, 0x24, 0x45, 0x27, 0x14, 0x2c, 0x65, 0x59, 0x22,
0xc3, 0xc6, 0xd1, 0xd2, 0x34, 0x9a, 0xc4, 0x20, 0x65, 0x59, 0x2c, 0xc3, 0x86, 0xdf, 0x03, 0x34,
0x5a, 0xd1, 0xbe, 0xb2, 0xaa, 0x44, 0x11, 0xf9, 0x51, 0xe2, 0xc8, 0xab, 0x03, 0x7c, 0x06, 0x51,
0x5b, 0x90, 0x88, 0x3d, 0x77, 0xcb, 0xe5, 0x27, 0x83, 0xf9, 0xb3, 0xc5, 0x82, 0x30, 0xd7, 0xad,
0xcb, 0x20, 0xf1, 0xa3, 0xc1, 0x9a, 0xf8, 0x02, 0x62, 0x45, 0x78, 0x16, 0x2c, 0x8d, 0xb2, 0xf1,
0x66, 0x1c, 0xa2, 0xad, 0x5d, 0x20, 0xe9, 0x07, 0xfc, 0x11, 0xa6, 0x2a, 0x1c, 0xb1, 0xfb, 0x83,
0x3a, 0x29, 0xfd, 0x2e, 0x06, 0x69, 0x94, 0x25, 0xf2, 0xaa, 0xc7, 0x5b, 0x4f, 0xf9, 0x0a, 0x66,
0x65, 0x53, 0x93, 0x39, 0x07, 0xd1, 0x9b, 0x91, 0x37, 0xa7, 0x3d, 0xdf, 0x06, 0xcc, 0x1f, 0x7e,
0xdc, 0xd9, 0x16, 0xb4, 0x57, 0x47, 0x9f, 0x35, 0x91, 0x93, 0x1e, 0xef, 0x0a, 0xca, 0x8f, 0xce,
0xfb, 0xbe, 0xb2, 0xf3, 0x86, 0xc1, 0xeb, 0x71, 0xf0, 0x16, 0x30, 0xb6, 0xd8, 0xa2, 0xad, 0xd1,
0x69, 0x62, 0x94, 0xb2, 0xec, 0xbf, 0x84, 0x0e, 0xed, 0x0a, 0x5a, 0xae, 0xe0, 0xfa, 0xcf, 0xd7,
0xd7, 0x95, 0xd1, 0xb5, 0x6f, 0xaa, 0x51, 0xc7, 0xae, 0x72, 0xb7, 0xdc, 0xbc, 0xc1, 0xbf, 0x3c,
0xfc, 0x26, 0xfe, 0x02, 0x93, 0x5f, 0xa7, 0xf8, 0x6d, 0x57, 0xcf, 0xa5, 0x26, 0x6f, 0xee, 0x2e,
0x0f, 0xc3, 0x8b, 0x0e, 0x23, 0x3f, 0x7c, 0xfa, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x49, 0x5b, 0x50,
0xf9, 0x04, 0x02, 0x00, 0x00,
// 623 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xdf, 0x4f, 0x13, 0x41,
0x10, 0xf6, 0x7a, 0x57, 0xda, 0x4e, 0x29, 0x96, 0x01, 0xcc, 0x02, 0x1a, 0x9a, 0x4b, 0x24, 0x47,
0x4c, 0x88, 0xa9, 0xf1, 0xd5, 0x50, 0x29, 0x9a, 0x1a, 0x14, 0xb2, 0x45, 0x5e, 0x2f, 0xdb, 0xbb,
0xc5, 0x6c, 0xd2, 0xde, 0xe1, 0xdd, 0x5e, 0x8d, 0xff, 0x93, 0x7f, 0x8e, 0x7f, 0x8b, 0xcf, 0x66,
0x7f, 0x5c, 0x29, 0xf4, 0x0c, 0x3e, 0x75, 0xe7, 0x9b, 0x6f, 0xbf, 0xf9, 0x76, 0x66, 0xae, 0xd0,
0x11, 0xc9, 0x24, 0x15, 0x11, 0x3f, 0xbe, 0xcd, 0x52, 0x99, 0x62, 0x5d, 0xff, 0xf8, 0x11, 0x78,
0x23, 0xc9, 0x67, 0xb8, 0x0d, 0x75, 0x29, 0xe4, 0x94, 0x13, 0xa7, 0xe7, 0x04, 0x2d, 0x6a, 0x02,
0x85, 0x46, 0x69, 0x91, 0x48, 0x52, 0xeb, 0x39, 0x81, 0x47, 0x4d, 0x80, 0x2f, 0x00, 0x8a, 0x44,
0xc8, 0xf0, 0x36, 0x13, 0x11, 0x27, 0xae, 0x4e, 0xb5, 0x14, 0x72, 0xa9, 0x00, 0xec, 0x82, 0x3b,
0x67, 0x92, 0x78, 0x1a, 0x57, 0x47, 0xff, 0x04, 0xd6, 0x4f, 0xd3, 0x44, 0xb2, 0x48, 0x5e, 0xa6,
0x22, 0x91, 0xf8, 0x0c, 0xd6, 0x66, 0x3c, 0x16, 0xc5, 0xcc, 0x56, 0xb3, 0x11, 0x12, 0x68, 0x44,
0x86, 0xa7, 0x0b, 0xb6, 0x68, 0x19, 0xfa, 0x7f, 0x6a, 0xd0, 0x18, 0x25, 0x73, 0xe5, 0x1f, 0x0f,
0xc0, 0x13, 0x92, 0xab, 0xbb, 0x6e, 0xd0, 0xee, 0xb7, 0xcd, 0x7b, 0x8e, 0xd5, 0x2b, 0xa8, 0x4e,
0xe0, 0x11, 0x74, 0x85, 0xe1, 0x66, 0xe1, 0x44, 0x4c, 0xa7, 0x22, 0xf9, 0x46, 0x6a, 0x3d, 0x37,
0x68, 0xd1, 0xa7, 0x25, 0xfe, 0xde, 0xc0, 0xf8, 0x6e, 0x89, 0x5a, 0x96, 0x76, 0xb5, 0xee, 0x96,
0xd5, 0x5d, 0x36, 0x7e, 0x77, 0xdf, 0xa2, 0xaa, 0x54, 0x54, 0xe4, 0x32, 0x9d, 0x2d, 0x95, 0xf2,
0x4c, 0xa9, 0x12, 0x2f, 0x4b, 0x1d, 0xc2, 0xe2, 0x76, 0x38, 0x67, 0x32, 0x14, 0x31, 0xa9, 0xeb,
0x47, 0x76, 0x4a, 0xf8, 0x9a, 0xc9, 0x51, 0xac, 0x78, 0x0b, 0x49, 0xcb, 0x5b, 0x33, 0xbc, 0x12,
0x36, 0xbc, 0x03, 0x68, 0x67, 0x7c, 0xce, 0xb3, 0x9c, 0x2b, 0x1a, 0x69, 0xf4, 0x9c, 0xa0, 0x49,
0xc1, 0x42, 0xd7, 0x4c, 0xe2, 0x2e, 0x34, 0x63, 0xf6, 0x33, 0x0f, 0xe3, 0x82, 0x93, 0x66, 0xcf,
0x09, 0x5c, 0xda, 0x50, 0xf1, 0xb0, 0xe0, 0x88, 0xe0, 0x89, 0x09, 0x4b, 0x48, 0x4b, 0x0b, 0xeb,
0xb3, 0x9a, 0x75, 0xfe, 0x43, 0xdc, 0x48, 0x02, 0x66, 0x03, 0x74, 0xe0, 0x9f, 0xc0, 0xf6, 0x69,
0xc6, 0x99, 0xe4, 0xb6, 0xfb, 0x94, 0x7f, 0x2f, 0x78, 0x2e, 0x31, 0x80, 0x86, 0xb5, 0xad, 0x67,
0xd8, 0xee, 0x6f, 0x94, 0x73, 0xb0, 0xbc, 0x32, 0xed, 0x1f, 0xc1, 0xce, 0x03, 0x85, 0xfc, 0x36,
0x4d, 0x72, 0xbd, 0x27, 0x85, 0x88, 0xed, 0x0a, 0xa8, 0xa3, 0xff, 0x12, 0x36, 0x3f, 0x72, 0xf9,
0xa0, 0xd2, 0x2a, 0xed, 0xb7, 0x03, 0xb8, 0xcc, 0xb3, 0x7a, 0xff, 0x6d, 0x09, 0xdf, 0x42, 0x3d,
0x97, 0x4c, 0x72, 0xbd, 0x65, 0x1b, 0xfd, 0x03, 0xcb, 0x5b, 0xd5, 0x3c, 0x1e, 0x2b, 0x1a, 0x35,
0x6c, 0xdc, 0x87, 0xd6, 0x8d, 0x48, 0xd8, 0x34, 0x54, 0x7e, 0x5c, 0xed, 0xa7, 0xa9, 0x81, 0xaf,
0x22, 0xf6, 0x4f, 0xa0, 0xae, 0xc9, 0xb8, 0x09, 0x9d, 0xf1, 0xd5, 0xe0, 0xea, 0x2c, 0x1c, 0x7d,
0xb9, 0x1e, 0x9c, 0x8f, 0x86, 0xdd, 0x27, 0x88, 0xb0, 0x61, 0xa0, 0x4b, 0x7a, 0xf1, 0xe1, 0x82,
0x7e, 0x1e, 0x74, 0x1d, 0xec, 0xc2, 0xba, 0xc1, 0xc6, 0x67, 0x83, 0xf3, 0xb3, 0x61, 0xb7, 0xe6,
0x07, 0xb0, 0x4d, 0x79, 0x12, 0xf3, 0xec, 0xd1, 0x06, 0xbc, 0x82, 0x9d, 0x07, 0x4c, 0xdb, 0x02,
0x04, 0x2f, 0x66, 0x92, 0x69, 0xee, 0x3a, 0xd5, 0x67, 0xff, 0x10, 0x70, 0xcc, 0xd9, 0xf4, 0x51,
0xd1, 0x1d, 0xd8, 0xba, 0xc7, 0x33, 0x92, 0xfd, 0x5f, 0xfa, 0xcb, 0xd3, 0xff, 0x1c, 0xf8, 0x09,
0x3a, 0xf7, 0x46, 0x89, 0xfb, 0xe5, 0x47, 0x52, 0xb1, 0x22, 0x7b, 0xcf, 0xab, 0x93, 0xd6, 0xea,
0x00, 0xe0, 0xae, 0xdf, 0x48, 0x2a, 0x46, 0x60, 0x54, 0x76, 0xff, 0x39, 0x1c, 0x3c, 0x87, 0xce,
0xbd, 0x36, 0x2c, 0xec, 0x54, 0xb5, 0x71, 0x61, 0xa7, 0xb2, 0x73, 0xaf, 0x1d, 0x1c, 0x42, 0x7b,
0xe9, 0xfd, 0x58, 0xd6, 0x5d, 0xed, 0xdd, 0xde, 0x5e, 0x55, 0xca, 0xe8, 0x4c, 0xd6, 0x74, 0xea,
0xcd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xba, 0xc3, 0xf1, 0x18, 0x6e, 0x05, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -249,6 +667,9 @@ const _ = grpc.SupportPackageIsVersion4
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type InboiceClient interface {
CreateInvoice(ctx context.Context, in *CreateInvoiceRequest, opts ...grpc.CallOption) (*CreateInvoiceResponse, error)
GetInvoice(ctx context.Context, in *GetInvoiceRequest, opts ...grpc.CallOption) (*GetInvoiceResponse, error)
RenderInvoice(ctx context.Context, in *RenderInvoiceRequest, opts ...grpc.CallOption) (Inboice_RenderInvoiceClient, error)
SealInvoice(ctx context.Context, in *SealInvoiceRequest, opts ...grpc.CallOption) (*SealInvoiceResponse, error)
}
type inboiceClient struct {
@ -268,9 +689,62 @@ func (c *inboiceClient) CreateInvoice(ctx context.Context, in *CreateInvoiceRequ
return out, nil
}
func (c *inboiceClient) GetInvoice(ctx context.Context, in *GetInvoiceRequest, opts ...grpc.CallOption) (*GetInvoiceResponse, error) {
out := new(GetInvoiceResponse)
err := c.cc.Invoke(ctx, "/proto.Inboice/GetInvoice", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *inboiceClient) RenderInvoice(ctx context.Context, in *RenderInvoiceRequest, opts ...grpc.CallOption) (Inboice_RenderInvoiceClient, error) {
stream, err := c.cc.NewStream(ctx, &_Inboice_serviceDesc.Streams[0], "/proto.Inboice/RenderInvoice", opts...)
if err != nil {
return nil, err
}
x := &inboiceRenderInvoiceClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type Inboice_RenderInvoiceClient interface {
Recv() (*RenderInvoiceResponse, error)
grpc.ClientStream
}
type inboiceRenderInvoiceClient struct {
grpc.ClientStream
}
func (x *inboiceRenderInvoiceClient) Recv() (*RenderInvoiceResponse, error) {
m := new(RenderInvoiceResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *inboiceClient) SealInvoice(ctx context.Context, in *SealInvoiceRequest, opts ...grpc.CallOption) (*SealInvoiceResponse, error) {
out := new(SealInvoiceResponse)
err := c.cc.Invoke(ctx, "/proto.Inboice/SealInvoice", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// InboiceServer is the server API for Inboice service.
type InboiceServer interface {
CreateInvoice(context.Context, *CreateInvoiceRequest) (*CreateInvoiceResponse, error)
GetInvoice(context.Context, *GetInvoiceRequest) (*GetInvoiceResponse, error)
RenderInvoice(*RenderInvoiceRequest, Inboice_RenderInvoiceServer) error
SealInvoice(context.Context, *SealInvoiceRequest) (*SealInvoiceResponse, error)
}
func RegisterInboiceServer(s *grpc.Server, srv InboiceServer) {
@ -295,6 +769,63 @@ func _Inboice_CreateInvoice_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler)
}
func _Inboice_GetInvoice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetInvoiceRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InboiceServer).GetInvoice(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/proto.Inboice/GetInvoice",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InboiceServer).GetInvoice(ctx, req.(*GetInvoiceRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Inboice_RenderInvoice_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(RenderInvoiceRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(InboiceServer).RenderInvoice(m, &inboiceRenderInvoiceServer{stream})
}
type Inboice_RenderInvoiceServer interface {
Send(*RenderInvoiceResponse) error
grpc.ServerStream
}
type inboiceRenderInvoiceServer struct {
grpc.ServerStream
}
func (x *inboiceRenderInvoiceServer) Send(m *RenderInvoiceResponse) error {
return x.ServerStream.SendMsg(m)
}
func _Inboice_SealInvoice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SealInvoiceRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InboiceServer).SealInvoice(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/proto.Inboice/SealInvoice",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InboiceServer).SealInvoice(ctx, req.(*SealInvoiceRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Inboice_serviceDesc = grpc.ServiceDesc{
ServiceName: "proto.Inboice",
HandlerType: (*InboiceServer)(nil),
@ -303,7 +834,21 @@ var _Inboice_serviceDesc = grpc.ServiceDesc{
MethodName: "CreateInvoice",
Handler: _Inboice_CreateInvoice_Handler,
},
{
MethodName: "GetInvoice",
Handler: _Inboice_GetInvoice_Handler,
},
{
MethodName: "SealInvoice",
Handler: _Inboice_SealInvoice_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "RenderInvoice",
Handler: _Inboice_RenderInvoice_Handler,
ServerStreams: true,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "inboice.proto",
}

121
render.go Normal file
View File

@ -0,0 +1,121 @@
package main
import (
"bytes"
"fmt"
"html/template"
"time"
wkhtml "github.com/SebastiaanKlippert/go-wkhtmltopdf"
"github.com/gobuffalo/packr"
pb "code.hackerspace.pl/q3k/inboice/proto"
)
var (
box = packr.NewBox("./templates")
invTmpl *template.Template
)
func init() {
inv := box.String("invoice.html")
invTmpl = template.Must(template.New("invoice.html").Parse(inv))
}
func renderInvoicePDF(i *pb.Invoice, number string, proforma bool) ([]byte, error) {
now := time.Now()
type item struct {
Title string
UnitPrice string
Qty string
VATRate string
TotalNet string
Total string
}
data := struct {
InvoiceNumber string
InvoicerBilling []string
InvoicerVAT string
InvoiceeBilling []string
InvoiceeVAT string
Date time.Time
DueDate time.Time
IBAN string
SWIFT string
Proforma bool
ReverseVAT bool
Items []item
TotalNet string
VATTotal string
Total string
DeliveryCharge string
}{
InvoiceNumber: number,
Date: now,
DueDate: now.AddDate(0, 0, int(i.DaysDue)),
IBAN: i.Iban,
SWIFT: i.Swift,
InvoicerVAT: i.InvoicerVatId,
InvoiceeVAT: i.CustomerVatId,
Proforma: proforma,
ReverseVAT: true,
InvoicerBilling: make([]string, len(i.InvoicerBilling)),
InvoiceeBilling: make([]string, len(i.CustomerBilling)),
}
unit := "€"
for d, s := range i.InvoicerBilling {
data.InvoicerBilling[d] = s
}
for d, s := range i.CustomerBilling {
data.InvoiceeBilling[d] = s
}
totalNet := 0
total := 0
for _, i := range i.Item {
rowTotalNet := int(i.UnitPrice * i.Count)
rowTotal := int(float64(rowTotalNet) * (float64(1) + float64(i.Vat)/100000))
totalNet += rowTotalNet
total += rowTotal
data.Items = append(data.Items, item{
Title: i.Title,
Qty: fmt.Sprintf("%d", i.Count),
UnitPrice: fmt.Sprintf(unit+"%.2f", float64(i.UnitPrice)/100),
VATRate: fmt.Sprintf("%.2f%%", float64(i.Vat)/1000),
TotalNet: fmt.Sprintf(unit+"%.2f", float64(rowTotalNet)/100),
Total: fmt.Sprintf(unit+"%.2f", float64(rowTotal)/100),
})
}
data.TotalNet = fmt.Sprintf(unit+"%.2f", float64(totalNet)/100)
data.VATTotal = fmt.Sprintf(unit+"%.2f", float64(total-totalNet)/100)
data.Total = fmt.Sprintf(unit+"%.2f", float64(total)/100)
data.DeliveryCharge = fmt.Sprintf(unit+"%.2f", float64(0))
var b bytes.Buffer
err := invTmpl.Execute(&b, &data)
if err != nil {
return []byte{}, err
}
pdfg, err := wkhtml.NewPDFGenerator()
if err != nil {
return []byte{}, err
}
pdfg.Dpi.Set(600)
pdfg.NoCollate.Set(false)
pdfg.PageSize.Set(wkhtml.PageSizeA4)
pdfg.AddPage(wkhtml.NewPageReader(&b))
if err := pdfg.Create(); err != nil {
return []byte{}, err
}
return pdfg.Bytes(), nil
}

181
templates/invoice.html Normal file
View File

@ -0,0 +1,181 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Invoice 0001</title>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,700" rel="stylesheet">
<style type="text/css">
body {
background-color: #fff;
font-family: 'Roboto', sans-serif;
font-size: 1em;
padding: 2em;
}
ul {
list-style: none;
padding: 0;
}
ul li {
margin-bottom: 0.2em;
}
@page {
size: A4;
margin: 0;
}
div.rhs {
float: right;
width: 50%;
text-align: right;
}
div.lhs {
float: left;
text-align: left;
width: 50%;
min-height: 35em;
}
div.metadata {
margin-top: 2em;
}
div.invoicee {
margin-top: 9em;
}
h1 {
font-size: 1.5em;
margin: 0;
text-transform: uppercase;
}
table.items {
text-align: right;
border-spacing: 0px;
border-collapse: collapse;
border: 0;
width: 100%;
}
table.items td,th {
border: 1px solid black;
}
table.items tr:first-child {
background-color: #eee;
color: #111;
padding: 0.8em;
text-align: left;
}
table.items td {
background-color: #fff;
}
table.items td,th {
padding: 0.5em 1em 0.5em 1em;
}
td.lhead {
border: 0 !important;
text-align: right;
text-transform: uppercase;
background: rgba(0, 0, 0, 0) !important;
}
div.bgtext {
z-index: -10;
position: absolute;
top: 140mm;
left: 0;
width: 100%;
}
div.bgtext div {
text-align: center;
font-size: 10em;
color: #ddd;
-webkit-transform: rotate(-45deg);
text-transform: uppercase;
}
</style>
</head>
<body>
{{ if .Proforma }}
<div class="bgtext"><div>Proforma</div></div>
{{ end }}
<div class="rhs">
<div class="invoicer">
<ul>
{{ range $i, $e := .InvoicerBilling }}
{{ if eq $i 0 }}
<li><b>{{ $e }}</b></li>
{{ else }}
<li>{{ $e }}</li>
{{ end }}
{{ end }}
<li><b>VAT Number:</b> {{ .InvoicerVAT }}</li>
</ul>
</div>
<div class="metadata">
<ul>
<li><b>Invoice number:</b> {{ .InvoiceNumber }}</li>
<li><b>Date:</b> {{ .Date.Format "2006/01/02" }}</li>
<li><b>Due date:</b> {{ .DueDate.Format "2006/01/02" }}</li>
<li><b>IBAN:</b> {{ .IBAN }}</li>
<li><b>SWIFT/BIC:</b> {{ .SWIFT }}</li>
</ul>
</div>
</div>
<div class="lhs">
<div class="invoicee">
{{ if .Proforma }}
<h1>Proforma Invoice:</h1>
{{ else }}
<h1>VAT Invoice:</h1>
{{ end }}
<ul>
{{ range $i, $e := .InvoiceeBilling }}
{{ if eq $i 0 }}
<li><b>{{ $e }}</b></li>
{{ else }}
<li>{{ $e }}</li>
{{ end }}
{{ end }}
<li>VAT Number: {{ .InvoiceeVAT }}</li>
{{ if .ReverseVAT }}
<li><b>(reverse charge applies)</b></li>
{{ end }}
</ul>
</div>
</div>
<div style="clear: both; height: 1em;"></div>
<table class="items">
<tr>
<th style="width: 60%;">Description</th>
<th>Price<br/>(ex. VAT)</th>
<th>Qty</th>
<th>VAT rate</th>
<th>Total<br />(net)</th>
<th>Total<br />(inc. VAT)</th>
</tr>
{{ range .Items }}
<tr>
<td style="text-align: left;">{{ .Title }}</td>
<td>{{ .UnitPrice }}</td>
<td>{{ .Qty }}</td>
<td>{{ .VATRate }}</td>
<td>{{ .TotalNet }}</td>
<td>{{ .Total }}</td>
</tr>
{{ end }}
<tr>
<td colspan="5" class="lhead">Net Total</td>
<td>{{ .TotalNet }}</td>
</tr>
<tr>
<td colspan="5" class="lhead">Delivery Charge</td>
<td>{{ .DeliveryCharge }}</td>
</tr>
<tr>
<td colspan="5" class="lhead">VAT Total{{ if .ReverseVAT }} (reverse charge applies){{ end }}</td>
<td>{{ .VATTotal }}</td>
</tr>
<tr>
<td colspan="5" class="lhead"><b>Total</b></td>
<td>{{ .Total }}</td>
</tr>
</table>
</body>
</html>