mock-acme 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mock_acme-0.1.0/CHANGELOG.md +60 -0
- mock_acme-0.1.0/LICENSE +21 -0
- mock_acme-0.1.0/MANIFEST.in +2 -0
- mock_acme-0.1.0/PKG-INFO +161 -0
- mock_acme-0.1.0/README.md +128 -0
- mock_acme-0.1.0/mock_acme.egg-info/PKG-INFO +161 -0
- mock_acme-0.1.0/mock_acme.egg-info/SOURCES.txt +35 -0
- mock_acme-0.1.0/mock_acme.egg-info/dependency_links.txt +1 -0
- mock_acme-0.1.0/mock_acme.egg-info/requires.txt +5 -0
- mock_acme-0.1.0/mock_acme.egg-info/top_level.txt +1 -0
- mock_acme-0.1.0/mockacme/__init__.py +23 -0
- mock_acme-0.1.0/mockacme/bank_messages.py +91 -0
- mock_acme-0.1.0/mockacme/invoice_check.py +285 -0
- mock_acme-0.1.0/mockacme/pay_invoices.py +394 -0
- mock_acme-0.1.0/mockacme/payment_run.py +1046 -0
- mock_acme-0.1.0/mockacme/po_bridge.py +159 -0
- mock_acme-0.1.0/mockacme/procure_to_pay.py +176 -0
- mock_acme-0.1.0/mockacme/remittance.py +172 -0
- mock_acme-0.1.0/pyproject.toml +46 -0
- mock_acme-0.1.0/setup.cfg +4 -0
- mock_acme-0.1.0/tests/__init__.py +120 -0
- mock_acme-0.1.0/tests/samples/external/LICENSE-Apache-2.0.txt +201 -0
- mock_acme-0.1.0/tests/samples/external/NOTICE-moov-ach.txt +17 -0
- mock_acme-0.1.0/tests/samples/external/SOURCES.md +31 -0
- mock_acme-0.1.0/tests/samples/external/bai2-sample1.txt +27 -0
- mock_acme-0.1.0/tests/samples/external/bai2-sample2.txt +31 -0
- mock_acme-0.1.0/tests/samples/external/bai2-sample3.txt +64 -0
- mock_acme-0.1.0/tests/samples/external/bai2-sample4.txt +116 -0
- mock_acme-0.1.0/tests/samples/external/bai2-sample5.txt +124 -0
- mock_acme-0.1.0/tests/samples/external/nacha-return-WEB.ach +10 -0
- mock_acme-0.1.0/tests/test_invoice_check.py +295 -0
- mock_acme-0.1.0/tests/test_pay_invoices.py +249 -0
- mock_acme-0.1.0/tests/test_payment_run.py +724 -0
- mock_acme-0.1.0/tests/test_payment_run_readers.py +459 -0
- mock_acme-0.1.0/tests/test_po_bridge.py +111 -0
- mock_acme-0.1.0/tests/test_procure_to_pay.py +449 -0
- mock_acme-0.1.0/tests/test_remittance.py +252 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Every release of [mock-acme](https://pypi.org/project/mock-acme/). The format
|
|
4
|
+
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
|
|
5
|
+
versions follow [semantic versioning](https://semver.org/spec/v2.0.0.html) -
|
|
6
|
+
while the major version is 0, a minor bump may change behaviour, and each entry
|
|
7
|
+
says so where it does.
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
Nothing yet.
|
|
12
|
+
|
|
13
|
+
## [0.1.0] - 2026-10-05
|
|
14
|
+
|
|
15
|
+
The first release.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **The integrations that lived in the mocks' `examples/` folders, in one
|
|
20
|
+
package** ([#1], [#4]). `mockacme.po_bridge` from mock-edi;
|
|
21
|
+
`mockacme.invoice_check` and `mockacme.remittance` from mock-sap;
|
|
22
|
+
`mockacme.pay_invoices`, `mockacme.payment_run`, `mockacme.procure_to_pay`
|
|
23
|
+
and the `mockacme.bank_messages` they share from mock-bank. Each mock has
|
|
24
|
+
removed its copy, starting with the release after mock-sap 0.17.1, mock-edi
|
|
25
|
+
0.7.0 and mock-bank 0.7.0. Anything that imported
|
|
26
|
+
`mockbank.examples.payment_run` imports `mockacme.payment_run` instead.
|
|
27
|
+
- **Tests that start the three mocks themselves** ([#1]). Importing `tests`
|
|
28
|
+
starts mock-sap, mock-edi and mock-bank on ports the operating system chose,
|
|
29
|
+
so there is nothing to start first and no port to keep free.
|
|
30
|
+
- **`payment_run`'s statement readers held to mock-bank's own writers**
|
|
31
|
+
([#6]), with moov-io's BAI2 and NACHA sample files.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
These differ from the last copies the mocks carried.
|
|
36
|
+
|
|
37
|
+
- **Money arriving is not posted to SAP as a payment coming back** ([#3]).
|
|
38
|
+
`payment_run` tells a returned payment from a received credit, and posts a
|
|
39
|
+
received credit without the reference it quotes, so that SAP does not reopen
|
|
40
|
+
a paid invoice. It records a problem on the run each time. This is a stopgap
|
|
41
|
+
until a `FINSTA01` can say which kind of credit a line is
|
|
42
|
+
(rseufert/mock-sap#89).
|
|
43
|
+
- **A statement is posted to SAP in its own currency** ([#3]). The `FINSTA01`
|
|
44
|
+
carried EUR whatever the statement said. A statement that names no currency
|
|
45
|
+
is not posted, and the run says so. A BAI2 statement with no currency on the
|
|
46
|
+
account or the group is read as USD.
|
|
47
|
+
|
|
48
|
+
### Known to be wrong
|
|
49
|
+
|
|
50
|
+
- **A second payment run started before the bank's statement is posted pays
|
|
51
|
+
the same invoice again** ([#2]). SAP has no state between open and cleared
|
|
52
|
+
for a run to write (rseufert/mock-sap#90). A test states this behaviour so
|
|
53
|
+
that it stays visible.
|
|
54
|
+
|
|
55
|
+
[0.1.0]: https://github.com/rseufert/mock-acme/releases/tag/v0.1.0
|
|
56
|
+
[#1]: https://github.com/rseufert/mock-acme/pull/1
|
|
57
|
+
[#2]: https://github.com/rseufert/mock-acme/issues/2
|
|
58
|
+
[#3]: https://github.com/rseufert/mock-acme/pull/3
|
|
59
|
+
[#4]: https://github.com/rseufert/mock-acme/pull/4
|
|
60
|
+
[#6]: https://github.com/rseufert/mock-acme/pull/6
|
mock_acme-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mock-acme contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mock_acme-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mock-acme
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The integration between the mocks: the middleware that mock-sap, mock-edi and mock-bank exist to test. Zero dependencies.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Repository, https://github.com/rseufert/mock-acme
|
|
7
|
+
Project-URL: Issues, https://github.com/rseufert/mock-acme/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/rseufert/mock-acme/blob/main/CHANGELOG.md
|
|
9
|
+
Keywords: sap,edi,x12,iso20022,procure-to-pay,reconciliation,integration,middleware,mock,testing
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
24
|
+
Classifier: Topic :: Software Development :: Testing
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: mock-sap>=0.17.0; extra == "test"
|
|
30
|
+
Requires-Dist: mock-edi; extra == "test"
|
|
31
|
+
Requires-Dist: mock-bank; extra == "test"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# mock-acme
|
|
35
|
+
|
|
36
|
+
**The integration between the mocks.** [mock-sap](https://github.com/rseufert/mock-sap),
|
|
37
|
+
[mock-edi](https://github.com/rseufert/mock-edi) and
|
|
38
|
+
[mock-bank](https://github.com/rseufert/mock-bank) stand in for systems you do
|
|
39
|
+
not own, so that the code between them can be tested. This is that code: ACME's
|
|
40
|
+
middleware, the fourth actor in every story the mocks tell.
|
|
41
|
+
|
|
42
|
+
It is not a mock, and it is not a client library to put in front of real money.
|
|
43
|
+
It is a reference: worked integrations, each with tests that run against the
|
|
44
|
+
released mocks, kept in one place so that there is one copy of each.
|
|
45
|
+
|
|
46
|
+
## What is here
|
|
47
|
+
|
|
48
|
+
| Module | Carries | Between |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `mockacme.po_bridge` | a purchase order out as an 850, the 855 back as an ORDRSP IDoc | SAP, supplier |
|
|
51
|
+
| `mockacme.invoice_check` | the supplier's 856 and 810, matched to the order, posted as an INVOIC IDoc or blocked | SAP, supplier |
|
|
52
|
+
| `mockacme.pay_invoices` | a supplier's 810s, paid as a pain.001 and followed to the statement | supplier, bank |
|
|
53
|
+
| `mockacme.payment_run` | SAP's open items, paid as a pain.001 or a NACHA file, cleared by posting the statement as a FINSTA01 | SAP, bank |
|
|
54
|
+
| `mockacme.remittance` | SAP's payment advice (a PEXR2002 it generates) out as an 820, and what the supplier made of it | SAP, supplier |
|
|
55
|
+
| `mockacme.procure_to_pay` | one purchase from the order to the cleared payment | all three |
|
|
56
|
+
|
|
57
|
+
`mockacme.bank_messages` is what the two payment modules share: the call to the
|
|
58
|
+
bank and the reading of its ISO 20022 answers.
|
|
59
|
+
|
|
60
|
+
Every module talks to the mocks over HTTP and imports none of them. The package
|
|
61
|
+
has no dependencies.
|
|
62
|
+
|
|
63
|
+
## Installing
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python3 -m pip install mock-acme
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
That installs the package and nothing else. The mocks it talks to are separate:
|
|
70
|
+
`pip install mock-sap mock-edi mock-bank`.
|
|
71
|
+
|
|
72
|
+
## Running the tests
|
|
73
|
+
|
|
74
|
+
From a checkout:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python3 -m pip install -e ".[test]"
|
|
78
|
+
python3 -m unittest discover -s tests -t . -v
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
That is the whole arrangement. Importing `tests` starts the three mocks, each on
|
|
82
|
+
a port the operating system chose, and stops them afterwards.
|
|
83
|
+
[`tests/__init__.py`](tests/__init__.py) says how to point the tests at a mock
|
|
84
|
+
that is already running, which is how they are run against a mock's `main`.
|
|
85
|
+
|
|
86
|
+
`tests/test_payment_run_readers.py` is the one test that imports a mock rather
|
|
87
|
+
than talking to it: it gives `payment_run`'s hand-written statement readers the
|
|
88
|
+
same statement mock-bank wrote as a `camt.053` and as BAI2, and five BAI2 files
|
|
89
|
+
from [moov-io/bai2](https://github.com/moov-io/bai2), and holds them to
|
|
90
|
+
mock-bank's own reader. The samples and their licence are in
|
|
91
|
+
[`tests/samples/external/`](tests/samples/external/SOURCES.md).
|
|
92
|
+
|
|
93
|
+
`payment_run` pays by ACH as well. The same tests in that mode:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
PAYMENT_RUN_FORMAT=nacha python3 -m unittest -v tests.test_payment_run
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The released mocks are what a pull request is tested against. A second
|
|
100
|
+
workflow, [`mocks-main.yml`](.github/workflows/mocks-main.yml), runs the same
|
|
101
|
+
tests every night against each mock's `main`, so that a change merged there
|
|
102
|
+
which breaks this code is seen before it is released. It is not a required
|
|
103
|
+
check; a red run there says something about another repository. To do the same
|
|
104
|
+
by hand:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
python3 -m pip install \
|
|
108
|
+
"mock-sap @ git+https://github.com/rseufert/mock-sap@main" \
|
|
109
|
+
"mock-edi @ git+https://github.com/rseufert/mock-edi@main" \
|
|
110
|
+
"mock-bank @ git+https://github.com/rseufert/mock-bank@main"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Known to be wrong
|
|
114
|
+
|
|
115
|
+
`payment_run` can pay an invoice twice: a second run started before the bank's
|
|
116
|
+
statement has been posted selects the same invoice again, and the bank pays it
|
|
117
|
+
again. SAP offers no state between open and cleared for a run to write
|
|
118
|
+
([mock-sap#90](https://github.com/rseufert/mock-sap/issues/90)), so this is not
|
|
119
|
+
fixed, and `tests/test_payment_run.py` has a test that says so. It is tracked
|
|
120
|
+
in [#2](https://github.com/rseufert/mock-acme/issues/2).
|
|
121
|
+
|
|
122
|
+
Money arriving is posted to SAP without the reference it quotes, so that SAP
|
|
123
|
+
does not take it for a returned payment and reopen an invoice. That is a
|
|
124
|
+
stopgap, said as a problem on the run each time it happens, until the FINSTA01
|
|
125
|
+
has a way to tell the two apart
|
|
126
|
+
([mock-sap#89](https://github.com/rseufert/mock-sap/issues/89)).
|
|
127
|
+
|
|
128
|
+
## Releasing
|
|
129
|
+
|
|
130
|
+
A release is the same three acts as in the mocks,
|
|
131
|
+
by one person in one sitting: merge a pull request that sets `version` in
|
|
132
|
+
`pyproject.toml` and `__version__` in `mockacme/__init__.py` and dates the
|
|
133
|
+
section in [`CHANGELOG.md`](CHANGELOG.md); tag that commit `v<version>`; publish
|
|
134
|
+
a GitHub Release from the tag. Publishing the Release runs
|
|
135
|
+
[`publish.yml`](.github/workflows/publish.yml), which runs the tests, builds,
|
|
136
|
+
refuses a tag that disagrees with the package, and uploads to PyPI through
|
|
137
|
+
Trusted Publishing. Running that workflow by hand uploads to TestPyPI instead.
|
|
138
|
+
|
|
139
|
+
There is no `tools/release.py` here as there is in the mocks: the steps are done
|
|
140
|
+
by hand, and CI checks only that the two places the version is written agree.
|
|
141
|
+
|
|
142
|
+
## Where the code came from
|
|
143
|
+
|
|
144
|
+
The modules were copied on 2026-10-04 from the `examples/` folder of the mock
|
|
145
|
+
each was written beside, with their tests; `remittance` was written there
|
|
146
|
+
afterwards and followed on 2026-10-05. Nothing in them changed but imports,
|
|
147
|
+
the lines saying how to run the tests, and issue references, which now name the
|
|
148
|
+
repository they belong to.
|
|
149
|
+
|
|
150
|
+
| Here | From | At |
|
|
151
|
+
| --- | --- | --- |
|
|
152
|
+
| `po_bridge`, its tests | mock-edi `examples/` | `0e86279` (0.7.0) |
|
|
153
|
+
| `invoice_check`, its tests | mock-sap `examples/` | `0ea524d` |
|
|
154
|
+
| `remittance`, its tests | mock-sap `examples/` | `73055a2` |
|
|
155
|
+
| `bank_messages`, `pay_invoices`, `payment_run`, `procure_to_pay`, their tests | mock-bank `examples/` | `fd618e6` (0.7.0) |
|
|
156
|
+
|
|
157
|
+
The originals were removed from those repositories on 2026-10-05, and each
|
|
158
|
+
left an `examples/README.md` saying which file became which. This is the only
|
|
159
|
+
copy.
|
|
160
|
+
|
|
161
|
+
The repository's settings are described in [docs/GITHUB.md](docs/GITHUB.md).
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# mock-acme
|
|
2
|
+
|
|
3
|
+
**The integration between the mocks.** [mock-sap](https://github.com/rseufert/mock-sap),
|
|
4
|
+
[mock-edi](https://github.com/rseufert/mock-edi) and
|
|
5
|
+
[mock-bank](https://github.com/rseufert/mock-bank) stand in for systems you do
|
|
6
|
+
not own, so that the code between them can be tested. This is that code: ACME's
|
|
7
|
+
middleware, the fourth actor in every story the mocks tell.
|
|
8
|
+
|
|
9
|
+
It is not a mock, and it is not a client library to put in front of real money.
|
|
10
|
+
It is a reference: worked integrations, each with tests that run against the
|
|
11
|
+
released mocks, kept in one place so that there is one copy of each.
|
|
12
|
+
|
|
13
|
+
## What is here
|
|
14
|
+
|
|
15
|
+
| Module | Carries | Between |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `mockacme.po_bridge` | a purchase order out as an 850, the 855 back as an ORDRSP IDoc | SAP, supplier |
|
|
18
|
+
| `mockacme.invoice_check` | the supplier's 856 and 810, matched to the order, posted as an INVOIC IDoc or blocked | SAP, supplier |
|
|
19
|
+
| `mockacme.pay_invoices` | a supplier's 810s, paid as a pain.001 and followed to the statement | supplier, bank |
|
|
20
|
+
| `mockacme.payment_run` | SAP's open items, paid as a pain.001 or a NACHA file, cleared by posting the statement as a FINSTA01 | SAP, bank |
|
|
21
|
+
| `mockacme.remittance` | SAP's payment advice (a PEXR2002 it generates) out as an 820, and what the supplier made of it | SAP, supplier |
|
|
22
|
+
| `mockacme.procure_to_pay` | one purchase from the order to the cleared payment | all three |
|
|
23
|
+
|
|
24
|
+
`mockacme.bank_messages` is what the two payment modules share: the call to the
|
|
25
|
+
bank and the reading of its ISO 20022 answers.
|
|
26
|
+
|
|
27
|
+
Every module talks to the mocks over HTTP and imports none of them. The package
|
|
28
|
+
has no dependencies.
|
|
29
|
+
|
|
30
|
+
## Installing
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
python3 -m pip install mock-acme
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
That installs the package and nothing else. The mocks it talks to are separate:
|
|
37
|
+
`pip install mock-sap mock-edi mock-bank`.
|
|
38
|
+
|
|
39
|
+
## Running the tests
|
|
40
|
+
|
|
41
|
+
From a checkout:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
python3 -m pip install -e ".[test]"
|
|
45
|
+
python3 -m unittest discover -s tests -t . -v
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
That is the whole arrangement. Importing `tests` starts the three mocks, each on
|
|
49
|
+
a port the operating system chose, and stops them afterwards.
|
|
50
|
+
[`tests/__init__.py`](tests/__init__.py) says how to point the tests at a mock
|
|
51
|
+
that is already running, which is how they are run against a mock's `main`.
|
|
52
|
+
|
|
53
|
+
`tests/test_payment_run_readers.py` is the one test that imports a mock rather
|
|
54
|
+
than talking to it: it gives `payment_run`'s hand-written statement readers the
|
|
55
|
+
same statement mock-bank wrote as a `camt.053` and as BAI2, and five BAI2 files
|
|
56
|
+
from [moov-io/bai2](https://github.com/moov-io/bai2), and holds them to
|
|
57
|
+
mock-bank's own reader. The samples and their licence are in
|
|
58
|
+
[`tests/samples/external/`](tests/samples/external/SOURCES.md).
|
|
59
|
+
|
|
60
|
+
`payment_run` pays by ACH as well. The same tests in that mode:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
PAYMENT_RUN_FORMAT=nacha python3 -m unittest -v tests.test_payment_run
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The released mocks are what a pull request is tested against. A second
|
|
67
|
+
workflow, [`mocks-main.yml`](.github/workflows/mocks-main.yml), runs the same
|
|
68
|
+
tests every night against each mock's `main`, so that a change merged there
|
|
69
|
+
which breaks this code is seen before it is released. It is not a required
|
|
70
|
+
check; a red run there says something about another repository. To do the same
|
|
71
|
+
by hand:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python3 -m pip install \
|
|
75
|
+
"mock-sap @ git+https://github.com/rseufert/mock-sap@main" \
|
|
76
|
+
"mock-edi @ git+https://github.com/rseufert/mock-edi@main" \
|
|
77
|
+
"mock-bank @ git+https://github.com/rseufert/mock-bank@main"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Known to be wrong
|
|
81
|
+
|
|
82
|
+
`payment_run` can pay an invoice twice: a second run started before the bank's
|
|
83
|
+
statement has been posted selects the same invoice again, and the bank pays it
|
|
84
|
+
again. SAP offers no state between open and cleared for a run to write
|
|
85
|
+
([mock-sap#90](https://github.com/rseufert/mock-sap/issues/90)), so this is not
|
|
86
|
+
fixed, and `tests/test_payment_run.py` has a test that says so. It is tracked
|
|
87
|
+
in [#2](https://github.com/rseufert/mock-acme/issues/2).
|
|
88
|
+
|
|
89
|
+
Money arriving is posted to SAP without the reference it quotes, so that SAP
|
|
90
|
+
does not take it for a returned payment and reopen an invoice. That is a
|
|
91
|
+
stopgap, said as a problem on the run each time it happens, until the FINSTA01
|
|
92
|
+
has a way to tell the two apart
|
|
93
|
+
([mock-sap#89](https://github.com/rseufert/mock-sap/issues/89)).
|
|
94
|
+
|
|
95
|
+
## Releasing
|
|
96
|
+
|
|
97
|
+
A release is the same three acts as in the mocks,
|
|
98
|
+
by one person in one sitting: merge a pull request that sets `version` in
|
|
99
|
+
`pyproject.toml` and `__version__` in `mockacme/__init__.py` and dates the
|
|
100
|
+
section in [`CHANGELOG.md`](CHANGELOG.md); tag that commit `v<version>`; publish
|
|
101
|
+
a GitHub Release from the tag. Publishing the Release runs
|
|
102
|
+
[`publish.yml`](.github/workflows/publish.yml), which runs the tests, builds,
|
|
103
|
+
refuses a tag that disagrees with the package, and uploads to PyPI through
|
|
104
|
+
Trusted Publishing. Running that workflow by hand uploads to TestPyPI instead.
|
|
105
|
+
|
|
106
|
+
There is no `tools/release.py` here as there is in the mocks: the steps are done
|
|
107
|
+
by hand, and CI checks only that the two places the version is written agree.
|
|
108
|
+
|
|
109
|
+
## Where the code came from
|
|
110
|
+
|
|
111
|
+
The modules were copied on 2026-10-04 from the `examples/` folder of the mock
|
|
112
|
+
each was written beside, with their tests; `remittance` was written there
|
|
113
|
+
afterwards and followed on 2026-10-05. Nothing in them changed but imports,
|
|
114
|
+
the lines saying how to run the tests, and issue references, which now name the
|
|
115
|
+
repository they belong to.
|
|
116
|
+
|
|
117
|
+
| Here | From | At |
|
|
118
|
+
| --- | --- | --- |
|
|
119
|
+
| `po_bridge`, its tests | mock-edi `examples/` | `0e86279` (0.7.0) |
|
|
120
|
+
| `invoice_check`, its tests | mock-sap `examples/` | `0ea524d` |
|
|
121
|
+
| `remittance`, its tests | mock-sap `examples/` | `73055a2` |
|
|
122
|
+
| `bank_messages`, `pay_invoices`, `payment_run`, `procure_to_pay`, their tests | mock-bank `examples/` | `fd618e6` (0.7.0) |
|
|
123
|
+
|
|
124
|
+
The originals were removed from those repositories on 2026-10-05, and each
|
|
125
|
+
left an `examples/README.md` saying which file became which. This is the only
|
|
126
|
+
copy.
|
|
127
|
+
|
|
128
|
+
The repository's settings are described in [docs/GITHUB.md](docs/GITHUB.md).
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mock-acme
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The integration between the mocks: the middleware that mock-sap, mock-edi and mock-bank exist to test. Zero dependencies.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Repository, https://github.com/rseufert/mock-acme
|
|
7
|
+
Project-URL: Issues, https://github.com/rseufert/mock-acme/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/rseufert/mock-acme/blob/main/CHANGELOG.md
|
|
9
|
+
Keywords: sap,edi,x12,iso20022,procure-to-pay,reconciliation,integration,middleware,mock,testing
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
24
|
+
Classifier: Topic :: Software Development :: Testing
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Provides-Extra: test
|
|
29
|
+
Requires-Dist: mock-sap>=0.17.0; extra == "test"
|
|
30
|
+
Requires-Dist: mock-edi; extra == "test"
|
|
31
|
+
Requires-Dist: mock-bank; extra == "test"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# mock-acme
|
|
35
|
+
|
|
36
|
+
**The integration between the mocks.** [mock-sap](https://github.com/rseufert/mock-sap),
|
|
37
|
+
[mock-edi](https://github.com/rseufert/mock-edi) and
|
|
38
|
+
[mock-bank](https://github.com/rseufert/mock-bank) stand in for systems you do
|
|
39
|
+
not own, so that the code between them can be tested. This is that code: ACME's
|
|
40
|
+
middleware, the fourth actor in every story the mocks tell.
|
|
41
|
+
|
|
42
|
+
It is not a mock, and it is not a client library to put in front of real money.
|
|
43
|
+
It is a reference: worked integrations, each with tests that run against the
|
|
44
|
+
released mocks, kept in one place so that there is one copy of each.
|
|
45
|
+
|
|
46
|
+
## What is here
|
|
47
|
+
|
|
48
|
+
| Module | Carries | Between |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| `mockacme.po_bridge` | a purchase order out as an 850, the 855 back as an ORDRSP IDoc | SAP, supplier |
|
|
51
|
+
| `mockacme.invoice_check` | the supplier's 856 and 810, matched to the order, posted as an INVOIC IDoc or blocked | SAP, supplier |
|
|
52
|
+
| `mockacme.pay_invoices` | a supplier's 810s, paid as a pain.001 and followed to the statement | supplier, bank |
|
|
53
|
+
| `mockacme.payment_run` | SAP's open items, paid as a pain.001 or a NACHA file, cleared by posting the statement as a FINSTA01 | SAP, bank |
|
|
54
|
+
| `mockacme.remittance` | SAP's payment advice (a PEXR2002 it generates) out as an 820, and what the supplier made of it | SAP, supplier |
|
|
55
|
+
| `mockacme.procure_to_pay` | one purchase from the order to the cleared payment | all three |
|
|
56
|
+
|
|
57
|
+
`mockacme.bank_messages` is what the two payment modules share: the call to the
|
|
58
|
+
bank and the reading of its ISO 20022 answers.
|
|
59
|
+
|
|
60
|
+
Every module talks to the mocks over HTTP and imports none of them. The package
|
|
61
|
+
has no dependencies.
|
|
62
|
+
|
|
63
|
+
## Installing
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python3 -m pip install mock-acme
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
That installs the package and nothing else. The mocks it talks to are separate:
|
|
70
|
+
`pip install mock-sap mock-edi mock-bank`.
|
|
71
|
+
|
|
72
|
+
## Running the tests
|
|
73
|
+
|
|
74
|
+
From a checkout:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python3 -m pip install -e ".[test]"
|
|
78
|
+
python3 -m unittest discover -s tests -t . -v
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
That is the whole arrangement. Importing `tests` starts the three mocks, each on
|
|
82
|
+
a port the operating system chose, and stops them afterwards.
|
|
83
|
+
[`tests/__init__.py`](tests/__init__.py) says how to point the tests at a mock
|
|
84
|
+
that is already running, which is how they are run against a mock's `main`.
|
|
85
|
+
|
|
86
|
+
`tests/test_payment_run_readers.py` is the one test that imports a mock rather
|
|
87
|
+
than talking to it: it gives `payment_run`'s hand-written statement readers the
|
|
88
|
+
same statement mock-bank wrote as a `camt.053` and as BAI2, and five BAI2 files
|
|
89
|
+
from [moov-io/bai2](https://github.com/moov-io/bai2), and holds them to
|
|
90
|
+
mock-bank's own reader. The samples and their licence are in
|
|
91
|
+
[`tests/samples/external/`](tests/samples/external/SOURCES.md).
|
|
92
|
+
|
|
93
|
+
`payment_run` pays by ACH as well. The same tests in that mode:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
PAYMENT_RUN_FORMAT=nacha python3 -m unittest -v tests.test_payment_run
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The released mocks are what a pull request is tested against. A second
|
|
100
|
+
workflow, [`mocks-main.yml`](.github/workflows/mocks-main.yml), runs the same
|
|
101
|
+
tests every night against each mock's `main`, so that a change merged there
|
|
102
|
+
which breaks this code is seen before it is released. It is not a required
|
|
103
|
+
check; a red run there says something about another repository. To do the same
|
|
104
|
+
by hand:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
python3 -m pip install \
|
|
108
|
+
"mock-sap @ git+https://github.com/rseufert/mock-sap@main" \
|
|
109
|
+
"mock-edi @ git+https://github.com/rseufert/mock-edi@main" \
|
|
110
|
+
"mock-bank @ git+https://github.com/rseufert/mock-bank@main"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Known to be wrong
|
|
114
|
+
|
|
115
|
+
`payment_run` can pay an invoice twice: a second run started before the bank's
|
|
116
|
+
statement has been posted selects the same invoice again, and the bank pays it
|
|
117
|
+
again. SAP offers no state between open and cleared for a run to write
|
|
118
|
+
([mock-sap#90](https://github.com/rseufert/mock-sap/issues/90)), so this is not
|
|
119
|
+
fixed, and `tests/test_payment_run.py` has a test that says so. It is tracked
|
|
120
|
+
in [#2](https://github.com/rseufert/mock-acme/issues/2).
|
|
121
|
+
|
|
122
|
+
Money arriving is posted to SAP without the reference it quotes, so that SAP
|
|
123
|
+
does not take it for a returned payment and reopen an invoice. That is a
|
|
124
|
+
stopgap, said as a problem on the run each time it happens, until the FINSTA01
|
|
125
|
+
has a way to tell the two apart
|
|
126
|
+
([mock-sap#89](https://github.com/rseufert/mock-sap/issues/89)).
|
|
127
|
+
|
|
128
|
+
## Releasing
|
|
129
|
+
|
|
130
|
+
A release is the same three acts as in the mocks,
|
|
131
|
+
by one person in one sitting: merge a pull request that sets `version` in
|
|
132
|
+
`pyproject.toml` and `__version__` in `mockacme/__init__.py` and dates the
|
|
133
|
+
section in [`CHANGELOG.md`](CHANGELOG.md); tag that commit `v<version>`; publish
|
|
134
|
+
a GitHub Release from the tag. Publishing the Release runs
|
|
135
|
+
[`publish.yml`](.github/workflows/publish.yml), which runs the tests, builds,
|
|
136
|
+
refuses a tag that disagrees with the package, and uploads to PyPI through
|
|
137
|
+
Trusted Publishing. Running that workflow by hand uploads to TestPyPI instead.
|
|
138
|
+
|
|
139
|
+
There is no `tools/release.py` here as there is in the mocks: the steps are done
|
|
140
|
+
by hand, and CI checks only that the two places the version is written agree.
|
|
141
|
+
|
|
142
|
+
## Where the code came from
|
|
143
|
+
|
|
144
|
+
The modules were copied on 2026-10-04 from the `examples/` folder of the mock
|
|
145
|
+
each was written beside, with their tests; `remittance` was written there
|
|
146
|
+
afterwards and followed on 2026-10-05. Nothing in them changed but imports,
|
|
147
|
+
the lines saying how to run the tests, and issue references, which now name the
|
|
148
|
+
repository they belong to.
|
|
149
|
+
|
|
150
|
+
| Here | From | At |
|
|
151
|
+
| --- | --- | --- |
|
|
152
|
+
| `po_bridge`, its tests | mock-edi `examples/` | `0e86279` (0.7.0) |
|
|
153
|
+
| `invoice_check`, its tests | mock-sap `examples/` | `0ea524d` |
|
|
154
|
+
| `remittance`, its tests | mock-sap `examples/` | `73055a2` |
|
|
155
|
+
| `bank_messages`, `pay_invoices`, `payment_run`, `procure_to_pay`, their tests | mock-bank `examples/` | `fd618e6` (0.7.0) |
|
|
156
|
+
|
|
157
|
+
The originals were removed from those repositories on 2026-10-05, and each
|
|
158
|
+
left an `examples/README.md` saying which file became which. This is the only
|
|
159
|
+
copy.
|
|
160
|
+
|
|
161
|
+
The repository's settings are described in [docs/GITHUB.md](docs/GITHUB.md).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
CHANGELOG.md
|
|
2
|
+
LICENSE
|
|
3
|
+
MANIFEST.in
|
|
4
|
+
README.md
|
|
5
|
+
pyproject.toml
|
|
6
|
+
mock_acme.egg-info/PKG-INFO
|
|
7
|
+
mock_acme.egg-info/SOURCES.txt
|
|
8
|
+
mock_acme.egg-info/dependency_links.txt
|
|
9
|
+
mock_acme.egg-info/requires.txt
|
|
10
|
+
mock_acme.egg-info/top_level.txt
|
|
11
|
+
mockacme/__init__.py
|
|
12
|
+
mockacme/bank_messages.py
|
|
13
|
+
mockacme/invoice_check.py
|
|
14
|
+
mockacme/pay_invoices.py
|
|
15
|
+
mockacme/payment_run.py
|
|
16
|
+
mockacme/po_bridge.py
|
|
17
|
+
mockacme/procure_to_pay.py
|
|
18
|
+
mockacme/remittance.py
|
|
19
|
+
tests/__init__.py
|
|
20
|
+
tests/test_invoice_check.py
|
|
21
|
+
tests/test_pay_invoices.py
|
|
22
|
+
tests/test_payment_run.py
|
|
23
|
+
tests/test_payment_run_readers.py
|
|
24
|
+
tests/test_po_bridge.py
|
|
25
|
+
tests/test_procure_to_pay.py
|
|
26
|
+
tests/test_remittance.py
|
|
27
|
+
tests/samples/external/LICENSE-Apache-2.0.txt
|
|
28
|
+
tests/samples/external/NOTICE-moov-ach.txt
|
|
29
|
+
tests/samples/external/SOURCES.md
|
|
30
|
+
tests/samples/external/bai2-sample1.txt
|
|
31
|
+
tests/samples/external/bai2-sample2.txt
|
|
32
|
+
tests/samples/external/bai2-sample3.txt
|
|
33
|
+
tests/samples/external/bai2-sample4.txt
|
|
34
|
+
tests/samples/external/bai2-sample5.txt
|
|
35
|
+
tests/samples/external/nacha-return-WEB.ach
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mockacme
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""mock-acme: the integration between the mocks.
|
|
2
|
+
|
|
3
|
+
ACME is the company in every story the mocks tell: the buyer that sends the
|
|
4
|
+
purchase order, the SAP system that owes the invoice, the account the bank
|
|
5
|
+
pays from. This package is ACME's middleware, the code that carries a document
|
|
6
|
+
from one system to the next:
|
|
7
|
+
|
|
8
|
+
po_bridge SAP purchase order -> 850 -> supplier; 855 -> SAP
|
|
9
|
+
invoice_check 856 and 810 from the supplier, matched to the order, posted to SAP
|
|
10
|
+
pay_invoices 810s from the supplier, paid through the bank
|
|
11
|
+
payment_run SAP's open items, paid through the bank and cleared by its statement
|
|
12
|
+
remittance SAP's payment advice -> 820 -> supplier
|
|
13
|
+
procure_to_pay all of it, across all three mocks
|
|
14
|
+
|
|
15
|
+
It is not a mock. mock-sap, mock-edi and mock-bank stand in for systems you do
|
|
16
|
+
not own so that code like this can be tested; this is that code. It talks to
|
|
17
|
+
them over HTTP and imports none of them.
|
|
18
|
+
|
|
19
|
+
It is a reference, not a client library to put in front of real money:
|
|
20
|
+
`payment_run` can still pay an invoice twice, in the way rseufert/mock-acme#2
|
|
21
|
+
says. Standard library only.
|
|
22
|
+
"""
|
|
23
|
+
__version__ = "0.1.0"
|