Friday, May 30, 2025

Main CT600 Submitter


So now it's time to create the main program to submit the CT600.

I think I'm going to want to be able to do "all" of the various operations - submit, see what's out there, check a submission, delete a submission - from a single program, and that means that I'm going to want an argument that is the "command". But most of the other arguments are going to be configuration files. That being the case, I'm going to work on the assumption that the command will have the syntax:
ct600 <operation> <config>...
But for now, I'm just going to assume the operation "submit" (in fact, just transmitting and expecting an error) and only parse configuration files. I'm going to rejig what we did last time to accept these configuration files and then consolidate the configuration before attempting to generate a message and submit it.

Let's go!

A New Command

We already have a command to generate GnuCash files, so we're going to do something very similar. So similar, in fact, I am just going to copy it and then update it.
package main

import (
    "fmt"
    "os"

    "github.com/gmmapowell/ignorance/accounts/internal/ct600/config"
    "github.com/gmmapowell/ignorance/accounts/internal/ct600/submission"
)

func main() {
    conf := config.MakeBlankConfig()
    for _, f := range os.Args[1:] {
        err := config.IncludeConfig(conf, f)
        if err != nil {
            fmt.Printf("failed to read config %s: %v\n", f, err)
            return
        }
    }
    err := submission.Submit(conf)
    if err != nil {
        fmt.Printf("submission failed: %v\n", err)
        return
    }
}

CT600_MAIN_SUBMITTER:accounts/cmd/ct600/main.go

This is quite big for a cmd program, but I think at this moment I'm happy with it. We'll see how we do when we add multiple commands; I imagine I will want to put basically all of it somewhere else.

So, as promised, I refactored the config stuff to make a blank configuration, then to incorporate each file we provide on the command line, and then we call Submit. I'm not going to review the configuration changes, but here is the submit code that has emerged from what was left of the test case (now deleted):
package submission

import (
    "fmt"
    "io"
    "log"
    "net/http"
    "strings"

    "github.com/gmmapowell/ignorance/accounts/internal/ct600/config"
)

func Submit(conf *config.Config) error {
    send, err := Generate(conf)
    if err != nil {
        return err
    }

    return transmit(send)
}

func transmit(body io.Reader) error {
    cli := &http.Client{}
    resp, err := cli.Post("https://test-transaction-engine.tax.service.gov.uk/submission", "application/x-binary", body)
    if err != nil {
        log.Fatalf("error posting xml file: %v", err)
    }
    respBody, err := io.ReadAll(resp.Body)
    if err != nil {
        log.Fatalf("error reading response: %v", err)
    }
    msg := string(respBody)
    fmt.Printf("%s", msg)
    if strings.Contains(msg, "GovTalkErrors") {
        return fmt.Errorf("there was a GovTalkErrors block")
    }

    return nil
}

CT600_MAIN_SUBMITTER:accounts/internal/ct600/submission/submit.go

Submit calls the existing Generate function, and then calls transmit, which is the old code from the test to send to the government website. This still has some constants in it (like the URL) that we will want to extract to configuration at some point (we will then need a set of "test" credentials and a set of "live" credentials in separate configuration files, going along with the URL and the GatewayTest flag). But for now, this is enough to get us running.

I put my valid credentials in a test file (of the same form as foo.json) and ran the ct600 script. And just like that, we have a "working" submission:
<?xml version="1.0" encoding="UTF-8"?>
<GovTalkMessage xmlns="http://www.govtalk.gov.uk/CM/envelope">
    <EnvelopeVersion>2.0</EnvelopeVersion>
    <Header>
        <MessageDetails>
            <Class>HMRC-CT-CT600</Class>
            <Qualifier>acknowledgement</Qualifier>
            <Function>submit</Function>
            <TransactionID></TransactionID>
            <CorrelationID>8E73E73CD1F34678BBFDE9B6C1B9139C</CorrelationID>
            <ResponseEndPoint PollInterval="10">https://test-transaction-engine.tax.service.gov.uk/poll</ResponseEndPoint>
            <GatewayTimestamp>2025-05-30T20:34:21.066</GatewayTimestamp>
        </MessageDetails>
        <SenderDetails/>
    </Header>
    <GovTalkDetails>
        <Keys/>
    </GovTalkDetails>
    <Body/>
</GovTalkMessage>
That is, my submission has been accepted for consideration. I imagine when I write the next line of code to go back and examine that submission, I imagine I will see that it was, in fact, rejected.

Conclusion

In what feels like no time at all we have replaced our scaffolding test with a main program and, with the judicious introduction of correct data, we are able to communicate with the government. Excellent progress. We now need to expand this program to accept commands so that we can check for existing submissions, see the results and clean up dead submissions.

No comments:

Post a Comment