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.
Files changed (37) hide show
  1. mock_acme-0.1.0/CHANGELOG.md +60 -0
  2. mock_acme-0.1.0/LICENSE +21 -0
  3. mock_acme-0.1.0/MANIFEST.in +2 -0
  4. mock_acme-0.1.0/PKG-INFO +161 -0
  5. mock_acme-0.1.0/README.md +128 -0
  6. mock_acme-0.1.0/mock_acme.egg-info/PKG-INFO +161 -0
  7. mock_acme-0.1.0/mock_acme.egg-info/SOURCES.txt +35 -0
  8. mock_acme-0.1.0/mock_acme.egg-info/dependency_links.txt +1 -0
  9. mock_acme-0.1.0/mock_acme.egg-info/requires.txt +5 -0
  10. mock_acme-0.1.0/mock_acme.egg-info/top_level.txt +1 -0
  11. mock_acme-0.1.0/mockacme/__init__.py +23 -0
  12. mock_acme-0.1.0/mockacme/bank_messages.py +91 -0
  13. mock_acme-0.1.0/mockacme/invoice_check.py +285 -0
  14. mock_acme-0.1.0/mockacme/pay_invoices.py +394 -0
  15. mock_acme-0.1.0/mockacme/payment_run.py +1046 -0
  16. mock_acme-0.1.0/mockacme/po_bridge.py +159 -0
  17. mock_acme-0.1.0/mockacme/procure_to_pay.py +176 -0
  18. mock_acme-0.1.0/mockacme/remittance.py +172 -0
  19. mock_acme-0.1.0/pyproject.toml +46 -0
  20. mock_acme-0.1.0/setup.cfg +4 -0
  21. mock_acme-0.1.0/tests/__init__.py +120 -0
  22. mock_acme-0.1.0/tests/samples/external/LICENSE-Apache-2.0.txt +201 -0
  23. mock_acme-0.1.0/tests/samples/external/NOTICE-moov-ach.txt +17 -0
  24. mock_acme-0.1.0/tests/samples/external/SOURCES.md +31 -0
  25. mock_acme-0.1.0/tests/samples/external/bai2-sample1.txt +27 -0
  26. mock_acme-0.1.0/tests/samples/external/bai2-sample2.txt +31 -0
  27. mock_acme-0.1.0/tests/samples/external/bai2-sample3.txt +64 -0
  28. mock_acme-0.1.0/tests/samples/external/bai2-sample4.txt +116 -0
  29. mock_acme-0.1.0/tests/samples/external/bai2-sample5.txt +124 -0
  30. mock_acme-0.1.0/tests/samples/external/nacha-return-WEB.ach +10 -0
  31. mock_acme-0.1.0/tests/test_invoice_check.py +295 -0
  32. mock_acme-0.1.0/tests/test_pay_invoices.py +249 -0
  33. mock_acme-0.1.0/tests/test_payment_run.py +724 -0
  34. mock_acme-0.1.0/tests/test_payment_run_readers.py +459 -0
  35. mock_acme-0.1.0/tests/test_po_bridge.py +111 -0
  36. mock_acme-0.1.0/tests/test_procure_to_pay.py +449 -0
  37. 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
@@ -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.
@@ -0,0 +1,2 @@
1
+ include LICENSE README.md CHANGELOG.md
2
+ recursive-include tests *.py *.md *.txt *.ach
@@ -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,5 @@
1
+
2
+ [test]
3
+ mock-sap>=0.17.0
4
+ mock-edi
5
+ mock-bank
@@ -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"