It occurs to me that I could simplify things and go back to the set of micro-accounts that I generated on microaccounts.uk and not submit any computations. Then we can see whether that works more consistently.
func Submit(conf *config.Config) error {
utr := conf.Utr
if utr == "" {
utr = conf.Business.TaxNum
}
ctr := &govtalk.IRenvelope{Business: conf.Business, ReturnType: "new",
Sender: "Company", // the type of business we are, I believe. The schema limits it to a handful of options
UTR: utr,
PeriodStart: "2025-01-01", PeriodEnd: "2025-12-31",
Turnover: 100000.0, TradingProfits: 0, LossesBroughtForward: 0, TradingNetProfits: 0,
CorporationTax: 0,
AccountsIXBRL: "ct600/11110000_accounts.html",
// AccountsIXBRL: "ct600/accounts-section.xml",
// ComputationIXBRL: "ct600/comps-section.xml",
// ComputationIXBRL: "ct600/ixbrl-sample-2.xml",
NoComputationsReason: "Not within charge to CT",
}
submitOptions := &govtalk.EnvelopeOptions{Qualifier: "request", Function: "submit", IncludeSender: true, IncludeKeys: true, IncludeBody: true, IRenvelope: ctr}
send, err := govtalk.Generate("submit.xml", false, conf, submitOptions)
if err != nil {
return err
}
msg, err := transmit(send)
if err != nil {
return err
}
decoder := xml.NewDecoder(bytes.NewReader(msg))
var data string
var waitFor time.Duration = 10
pollOn := config.MakeBlankConfig()
for tok, err := decoder.Token(); err == nil; tok, err = decoder.Token() {
switch tok := tok.(type) {
case xml.StartElement:
switch tok.Name.Local {
case "ResponseEndPoint":
for _, a := range tok.Attr {
if a.Name.Local == "PollInterval" {
log.Printf("ResponseEndPoint PollInterval: %s\n", a.Value)
tmp, err := strconv.Atoi(a.Value)
if err != nil {
log.Printf("failed to parse number %s\n", a.Value)
} else {
waitFor = time.Duration(tmp)
}
}
}
}
case xml.EndElement:
switch tok.Name.Local {
case "Function":
log.Printf("Function: %s\n", data)
case "Qualifier":
log.Printf("Qualifier: %s\n", data)
case "CorrelationID":
log.Printf("CorrelationID: %s\n", data)
pollOn.CorrelationID = data
case "ResponseEndPoint":
log.Printf("ResponseEndPoint: %s\n", data)
pollOn.PollURI = data
}
case xml.CharData:
data = string(tok)
}
}
time.Sleep(waitFor * time.Second)
Poll(pollOn)
return nil
}
CT600_SUBMIT_MICRO:accounts/internal/ct600/submission/submit.go
And when I do this, I get a different result again:2026/01/21 19:25:24 Qualifier: acknowledgementAnd, suddenly, everything becomes clear: those "positive" results I've been seeing haven't been positive at all. They were just deferred negatives: that is, they were saying "I don't have an answer for you yet; come back in another 10s". An actual positive result has a completed Body element with a signature and messages.
2026/01/21 19:25:24 Function: submit
2026/01/21 19:25:24 CorrelationID: 886AE85484A14569B43358844F8EF515
2026/01/21 19:25:24 ResponseEndPoint PollInterval: 10
2026/01/21 19:25:24 ResponseEndPoint: https://test-transaction-engine.tax.service.gov.uk/poll
2026/01/21 19:25:34 <?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>response</Qualifier><Function>submit</Function><TransactionID></TransactionID><CorrelationID>886AE85484A14569B43358844F8EF515</CorrelationID><ResponseEndPoint PollInterval="10">https://test-transaction-engine.tax.service.gov.uk/submission</ResponseEndPoint><Transformation>XML</Transformation><GatewayTimestamp>2026-01-21T19:25:34.815</GatewayTimestamp></MessageDetails><SenderDetails/></Header><GovTalkDetails><Keys></Keys></GovTalkDetails><Body><SuccessResponse xmlns="http://www.inlandrevenue.gov.uk/SuccessResponse"><IRmarkReceipt><dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"><dsig:SignedInfo><dsig:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></dsig:CanonicalizationMethod><dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></dsig:SignatureMethod><dsig:Reference><dsig:Transforms><dsig:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"><dsig:XPath>(count(ancestor-or-self::node()|/gti:GovTalkMessage/gti:Body)=count(ancestor-or-self::node())) and (count(ancestor-or-self::node()|/gti:GovTalkMessage/gti:Body/[name()='IRenvelope']/[name()='IRheader']/*[name()='IRmark'])!=count(ancestor-or-self::node()))</dsig:XPath></dsig:Transform><dsig:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></dsig:Transform></dsig:Transforms><dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></dsig:DigestMethod><dsig:DigestValue>MLuPohVdnhN+5rSvo3GdyT8PYFo=</dsig:DigestValue></dsig:Reference></dsig:SignedInfo><dsig:SignatureValue>w8RMS+vhauwMoZNxNpeQCBIGmBX4ZrNLswRCH+5tNooB1zjB+gdon7xFgzNo6NYRqZhKBjcBQ3fD
8nvOM/gMlsnTzgwsAvxroF2F2ea4nNQdS7xH4ONQzX3YI2FNo6lsB9+Dg55LYrm5vPyVF4STIrKS
MbdN8aJRmbPonNCihVR52/eJ9G6GV9DAYPlKX+qcX3i2L6O6mmLCyfEw+i0+OHRpYZLaNg/23bva
ui4GuhU9LKv4m78lEGOyC6RIUEGpZk1HFSlPfhU98hkHJuPuHLVl/j7DJxhOtXbyTNMGLMQKtws7
zYWTRwRVdkHtLabysDGo++a3P6L1i5dc5d83/g==</dsig:SignatureValue><dsig:KeyInfo><dsig:X509Data><dsig:X509Certificate>MIIG1DCCBbygAwIBAgIQAXlGdOaNS07zg7WUCv1YHDANBgkqhkiG9w0BAQsFADBZMQswCQYDVQQG
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMTMwMQYDVQQDEypEaWdpQ2VydCBHbG9iYWwgRzIg
VExTIFJTQSBTSEEyNTYgMjAyMCBDQTEwHhcNMjUwNzI1MDAwMDAwWhcNMjYwODI1MjM1OTU5WjBe
MQswCQYDVQQGEwJHQjEPMA0GA1UEBxMGTG9uZG9uMR8wHQYDVQQKExZITSBSZXZlbnVlIGFuZCBD
dXN0b21zMR0wGwYDVQQDExRpcmE3NDgzNy5obXJjLmdvdi51azCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAOsinZ11A32r4dVz3yX63ePFY7uabzWncwKR4ZeHDp50b9LsFS1/4+H50vsc
V73BD/WL7Dkq0x8tYaQKBzj3A9E5KQNLhtlPR/HbjmL91c8C/PVvEwoxWUOMMJSvt9ie0YVX8nKa
VJfRILfqh8RyfWgxqT/6o5VFHmo233Dmx1TKPqPNzTqsu+ereAcHk9jLy63GXBVf0UZ64i1/dSIm
47VixZogwHkxqgcAIRhI9hZNdSzpBAishe5tdYW2mDwGSjsT4s/XXAItztrfsQgsEim1y4QylYRK
bis1bemYknj/rOfShviF270NI1D05hvi6/p3QHwWmnkCRT+mGYa/nLcCAwEAAaOCA5EwggONMB8G
A1UdIwQYMBaAFHSFgMBmx9833s+9KTeqAx2+7c0XMB0GA1UdDgQWBBQ3M7FFraa3yHrDZrOtwvdZ
J0+WKjAfBgNVHREEGDAWghRpcmE3NDgzNy5obXJjLmdvdi51azA+BgNVHSAENzA1MDMGBmeBDAEC
AjApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjCBnwYDVR0fBIGXMIGUMEigRqBEhkJo
dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRHbG9iYWxHMlRMU1JTQVNIQTI1NjIwMjBD
QTEtMS5jcmwwSKBGoESGQmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcy
VExTUlNBU0hBMjU2MjAyMENBMS0xLmNybDCBhwYIKwYBBQUHAQEEezB5MCQGCCsGAQUFBzABhhho
dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wUQYIKwYBBQUHMAKGRWh0dHA6Ly9jYWNlcnRzLmRpZ2lj
ZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbEcyVExTUlNBU0hBMjU2MjAyMENBMS0xLmNydDAMBgNVHRMB
Af8EAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdQDXbX0Q0af1d8LH6V/XAL/5gskzWmXh
0LMBcxfAyMVpdwAAAZhCMS7MAAAEAwBGMEQCICXglyjFEQqtO4utp9X05bRcKqX2IRSbRARNQerW
M7ldAiBzNoFRirdcAF8AbSAvr2RS0IK4qlkq66eQAijyw5j8ggB3AMIxfldFGaNF7n843rKQQevH
wiFaIr9/1bWtdprZDlLNAAABmEIxLwoAAAQDAEgwRgIhAJ7N3qWEzN5sRjeiStCNiARFHFFfZE8P
vJqnSArOnWytAiEA6rBJlBVQedIu/rEKeybndcGSt75Emne634xyrH/dNA4AdwCUTkOH+uzB74Hz
GSQmqBhlAcfTXzgCAT9yZ31VNy4Z2AAAAZhCMS8eAAAEAwBIMEYCIQC+TF9LUDY8I+2IlguM3a9E
wtHuhYMop3/K/qTh0428fAIhALQcptxsZTQte36EU7ulrFu8SZejwtI7NHJ+KbM2z8ZoMA0GCSqG
SIb3DQEBCwUAA4IBAQBHFr3J/EH0xKZl6Lsn8HClBCnRvJKz2QzRfuVtIGxVenISLdS11h5gEhyG
T2mE5gvlz9Eop9GkFNwGa7AOMq4hUaDZrBhEFUxqPHqrQDzhlnQdnLSNlynw3I4LA/CaUQH4yy06
9TkHJf4tGx2n/uMnYljLt0Ipn8qXRUu2U/M1WQnlPLzeudNpinI5MIC/0yVofvpRWFh5k/YK+cbz
GE8nPDvlpxakYT3hVrCLGHTQwPlKKzb+i2B2UPtcD4JdY8Za4KRDcl4UH3FDEaEw7IyIsCTU3NA/
C0n9Y/lRZpWoFF9CSYy0lS+3UhJK+HNIXIKNnfGC1rqxGhs+9Wim/UVB</dsig:X509Certificate></dsig:X509Data></dsig:KeyInfo></dsig:Signature><Message code="0000">HMRC has received the HMRC-CT-CT600 document ref: 8596148860 at 19.25 on 21/01/2026. The associated IRmark was: GC5Y7IQVLWPBG7XGWSX2G4M5ZE7Q6YC2. We strongly recommend that you keep this receipt electronically, and we advise that you also keep your submission electronically for your records. They are evidence of the information that you submitted to HMRC.</Message></IRmarkReceipt><Message code="077001">Thank you for your submission</Message><AcceptedTime>2026-01-21T19:25:24.748</AcceptedTime></SuccessResponse></Body></GovTalkMessage>
OK, let's avoid running into this in future by handling the "deferred" error message.
This turns out to be a significantly bigger change than I had expected, because the etree library makes it much easier to parse the responses from the government's website. So that pushes me into refactoring the code that processes the response in submit.
So, for all the actual changes, this is really just a question of adding a for loop around the polling code and checking whether a message body came back:
for {
var waitFor time.Duration = 1
pollOn := config.MakeBlankConfig()
details := elt.FindElement("/GovTalkMessage/Header/MessageDetails")
qualifier := details.FindElement("Qualifier")
log.Printf("Qualifier: %s", qualifier.Text())
function := details.FindElement("Function")
log.Printf("Function: %s", function.Text())
pollOn.CorrelationID = details.FindElement("CorrelationID").Text()
log.Printf("CorrelationID: %s\n", pollOn.CorrelationID)
rep := details.FindElement("ResponseEndPoint")
if rep == nil {
panic("not found")
}
a := rep.SelectAttr("PollInterval")
tmp, err := strconv.Atoi(a.Value)
if err != nil {
log.Printf("failed to parse number %s\n", a.Value)
} else {
log.Printf("ResponseEndPoint PollInterval: %s\n", a.Value)
waitFor = time.Duration(tmp)
}
pollOn.PollURI = rep.Text()
log.Printf("ResponseEndPoint: %s\n", rep.Text())
time.Sleep(waitFor * time.Second)
elt, err = Poll(pollOn)
if elt == nil || err != nil {
return err
}
}
CT600_CHECK_RESPONSE_BODY:accounts/internal/ct600/submission/submit.go
Of course, now it "works" (read fails) every time, but I can work around that by hacking in a value of waitFor (say 1s) and check that it repeats (about 7 times at the moment, it would seem).But, ah, that feels so good.
No comments:
Post a Comment