TRON -> TRON_MAINNET
This commit is contained in:
@@ -217,8 +217,14 @@ func (s *Service) BatchResolveDocuments(ctx context.Context, req *documentsv1.Ba
|
||||
for _, ref := range refs {
|
||||
meta := &documentsv1.DocumentMeta{PaymentRef: ref}
|
||||
if record := recordByRef[ref]; record != nil {
|
||||
meta.AvailableTypes = toProtoTypes(record.Available)
|
||||
meta.ReadyTypes = toProtoTypes(record.Ready)
|
||||
record.Normalize()
|
||||
available := []model.DocumentType{model.DocumentTypeAct}
|
||||
ready := make([]model.DocumentType, 0, 1)
|
||||
if path, ok := record.StoragePaths[model.DocumentTypeAct]; ok && path != "" {
|
||||
ready = append(ready, model.DocumentTypeAct)
|
||||
}
|
||||
meta.AvailableTypes = toProtoTypes(available)
|
||||
meta.ReadyTypes = toProtoTypes(ready)
|
||||
}
|
||||
items = append(items, meta)
|
||||
}
|
||||
@@ -294,8 +300,9 @@ func (s *Service) GetDocument(ctx context.Context, req *documentsv1.GetDocumentR
|
||||
record.Normalize()
|
||||
|
||||
targetType := model.DocumentTypeFromProto(docType)
|
||||
if !containsDocType(record.Available, targetType) {
|
||||
return nil, status.Error(codes.NotFound, "document type not available")
|
||||
|
||||
if docType != documentsv1.DocumentType_DOCUMENT_TYPE_ACT {
|
||||
return nil, status.Error(codes.Unimplemented, "document type not implemented")
|
||||
}
|
||||
|
||||
if path, ok := record.StoragePaths[targetType]; ok && path != "" {
|
||||
@@ -310,10 +317,6 @@ func (s *Service) GetDocument(ctx context.Context, req *documentsv1.GetDocumentR
|
||||
}, nil
|
||||
}
|
||||
|
||||
if docType != documentsv1.DocumentType_DOCUMENT_TYPE_ACT {
|
||||
return nil, status.Error(codes.Unimplemented, "document type not implemented")
|
||||
}
|
||||
|
||||
content, hash, genErr := s.generateActPDF(record.Snapshot)
|
||||
if genErr != nil {
|
||||
logger.Warn("Failed to generate document", zap.Error(genErr))
|
||||
@@ -328,7 +331,6 @@ func (s *Service) GetDocument(ctx context.Context, req *documentsv1.GetDocumentR
|
||||
|
||||
record.StoragePaths[targetType] = path
|
||||
record.Hashes[targetType] = hash
|
||||
record.Ready = appendUnique(record.Ready, targetType)
|
||||
if updateErr := s.storage.Documents().Update(ctx, record); updateErr != nil {
|
||||
logger.Warn("Failed to update document record", zap.Error(updateErr))
|
||||
return nil, status.Error(codes.Internal, updateErr.Error())
|
||||
@@ -375,24 +377,7 @@ func (s *Service) generateActPDF(snapshot model.ActSnapshot) ([]byte, string, er
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
fileHash := sha256.Sum256(finalBytes)
|
||||
return finalBytes, hex.EncodeToString(fileHash[:]), nil
|
||||
}
|
||||
|
||||
func containsDocType(list []model.DocumentType, target model.DocumentType) bool {
|
||||
for _, entry := range list {
|
||||
if entry == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func appendUnique(list []model.DocumentType, value model.DocumentType) []model.DocumentType {
|
||||
if containsDocType(list, value) {
|
||||
return list
|
||||
}
|
||||
return append(list, value)
|
||||
return finalBytes, footerHex, nil
|
||||
}
|
||||
|
||||
func toProtoTypes(types []model.DocumentType) []documentsv1.DocumentType {
|
||||
|
||||
@@ -3,8 +3,6 @@ package documents
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -100,14 +98,11 @@ func TestGetDocument_IdempotentAndHashed(t *testing.T) {
|
||||
ExecutorFullName: "Jane Doe",
|
||||
Amount: decimal.RequireFromString("100.00"),
|
||||
Currency: "USD",
|
||||
OrgLegalName: "Acme Corp",
|
||||
OrgAddress: "42 Galaxy Way",
|
||||
}
|
||||
|
||||
record := &model.DocumentRecord{
|
||||
PaymentRef: "PAY-123",
|
||||
Snapshot: snapshot,
|
||||
Available: []model.DocumentType{model.DocumentTypeAct},
|
||||
}
|
||||
|
||||
documentsStore := &stubDocumentsStore{record: record}
|
||||
@@ -144,12 +139,15 @@ func TestGetDocument_IdempotentAndHashed(t *testing.T) {
|
||||
t.Fatalf("expected content on first call")
|
||||
}
|
||||
|
||||
hash1 := sha256.Sum256(resp1.Content)
|
||||
stored := record.Hashes[model.DocumentTypeAct]
|
||||
if stored == "" {
|
||||
t.Fatalf("expected stored hash")
|
||||
}
|
||||
if stored != hex.EncodeToString(hash1[:]) {
|
||||
footerHash := extractFooterHash(resp1.Content)
|
||||
if footerHash == "" {
|
||||
t.Fatalf("expected footer hash in PDF")
|
||||
}
|
||||
if stored != footerHash {
|
||||
t.Fatalf("stored hash mismatch: got %s", stored)
|
||||
}
|
||||
|
||||
@@ -174,3 +172,24 @@ func TestGetDocument_IdempotentAndHashed(t *testing.T) {
|
||||
t.Fatalf("expected document load on second call")
|
||||
}
|
||||
}
|
||||
|
||||
func extractFooterHash(pdf []byte) string {
|
||||
prefix := []byte("Document integrity hash: ")
|
||||
idx := bytes.Index(pdf, prefix)
|
||||
if idx == -1 {
|
||||
return ""
|
||||
}
|
||||
start := idx + len(prefix)
|
||||
end := start
|
||||
for end < len(pdf) && isHexDigit(pdf[end]) {
|
||||
end++
|
||||
}
|
||||
if end-start != 64 {
|
||||
return ""
|
||||
}
|
||||
return string(pdf[start:end])
|
||||
}
|
||||
|
||||
func isHexDigit(b byte) bool {
|
||||
return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F')
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ func TestTemplateRenderer_Render(t *testing.T) {
|
||||
ExecutorFullName: "Jane Doe",
|
||||
Amount: decimal.RequireFromString("123.45"),
|
||||
Currency: "USD",
|
||||
OrgLegalName: "Acme Corp",
|
||||
OrgAddress: "42 Galaxy Way",
|
||||
}
|
||||
|
||||
blocks, err := tmpl.Render(snapshot)
|
||||
@@ -54,15 +52,15 @@ func TestTemplateRenderer_Render(t *testing.T) {
|
||||
if kv == nil {
|
||||
t.Fatalf("expected kv block")
|
||||
}
|
||||
foundOrg := false
|
||||
foundExecutor := false
|
||||
for _, row := range kv.Rows {
|
||||
if len(row) >= 2 && row[0] == "Customer" && row[1] == snapshot.OrgLegalName {
|
||||
foundOrg = true
|
||||
if len(row) >= 2 && row[0] == "Executor" && row[1] == snapshot.ExecutorFullName {
|
||||
foundExecutor = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundOrg {
|
||||
t.Fatalf("expected org name in kv block")
|
||||
if !foundExecutor {
|
||||
t.Fatalf("expected executor name in kv block")
|
||||
}
|
||||
|
||||
table := findBlock(blocks, renderer.TagTable)
|
||||
|
||||
@@ -46,8 +46,6 @@ type ActSnapshot struct {
|
||||
ExecutorFullName string `bson:"executorFullName" json:"executorFullName"`
|
||||
Amount decimal.Decimal `bson:"amount" json:"amount"`
|
||||
Currency string `bson:"currency" json:"currency"`
|
||||
OrgLegalName string `bson:"orgLegalName" json:"orgLegalName"`
|
||||
OrgAddress string `bson:"orgAddress" json:"orgAddress"`
|
||||
}
|
||||
|
||||
func (s *ActSnapshot) Normalize() {
|
||||
@@ -57,8 +55,6 @@ func (s *ActSnapshot) Normalize() {
|
||||
s.PaymentID = strings.TrimSpace(s.PaymentID)
|
||||
s.ExecutorFullName = strings.TrimSpace(s.ExecutorFullName)
|
||||
s.Currency = strings.TrimSpace(s.Currency)
|
||||
s.OrgLegalName = strings.TrimSpace(s.OrgLegalName)
|
||||
s.OrgAddress = strings.TrimSpace(s.OrgAddress)
|
||||
}
|
||||
|
||||
// DocumentRecord stores document metadata and cached artefacts for a payment.
|
||||
@@ -66,8 +62,6 @@ type DocumentRecord struct {
|
||||
storable.Base `bson:",inline" json:",inline"`
|
||||
PaymentRef string `bson:"paymentRef" json:"paymentRef"`
|
||||
Snapshot ActSnapshot `bson:"snapshot" json:"snapshot"`
|
||||
Available []DocumentType `bson:"availableTypes,omitempty" json:"availableTypes,omitempty"`
|
||||
Ready []DocumentType `bson:"readyTypes,omitempty" json:"readyTypes,omitempty"`
|
||||
StoragePaths map[DocumentType]string `bson:"storagePaths,omitempty" json:"storagePaths,omitempty"`
|
||||
Hashes map[DocumentType]string `bson:"hashes,omitempty" json:"hashes,omitempty"`
|
||||
}
|
||||
|
||||
@@ -34,12 +34,6 @@ func NewDocuments(logger mlogger.Logger, db *mongo.Database) (*Documents, error)
|
||||
Keys: []ri.Key{{Field: "paymentRef", Sort: ri.Asc}},
|
||||
Unique: true,
|
||||
},
|
||||
{
|
||||
Keys: []ri.Key{{Field: "availableTypes", Sort: ri.Asc}},
|
||||
},
|
||||
{
|
||||
Keys: []ri.Key{{Field: "readyTypes", Sort: ri.Asc}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, def := range indexes {
|
||||
|
||||
@@ -19,9 +19,6 @@ PARTIES
|
||||
This Act is made between the following Parties.
|
||||
|
||||
#kv
|
||||
Customer | {{ .OrgLegalName }}
|
||||
Address | {{ .OrgAddress }}
|
||||
|
||||
Executor | {{ .ExecutorFullName }}
|
||||
Status | Individual
|
||||
|
||||
|
||||
Reference in New Issue
Block a user