-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#272] Added Billing-related Domains. #269
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ODORA0. Since this is not connected to any Iniz GitHub issue, I'll ask you to provide a comprehensive description of what all this PR bring in, could you do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
api-2.4/pom.xml
Outdated
@@ -16,6 +16,7 @@ | |||
|
|||
<properties> | |||
<openmrsPlatformVersion>${openmrsVersion2.4}</openmrsPlatformVersion> | |||
<billingVersion>1.1.0-SNAPSHOT</billingVersion> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We assume that there is plans for a v1.1.0
release?
.../src/main/java/org/openmrs/module/initializer/api/billing/BillableServicesLineProcessor.java
Outdated
Show resolved
Hide resolved
api-2.4/src/main/java/org/openmrs/module/initializer/api/billing/CashPointCsvParser.java
Outdated
Show resolved
Hide resolved
api-2.4/src/main/java/org/openmrs/module/initializer/api/billing/CashPointLoader.java
Outdated
Show resolved
Hide resolved
.../src/main/java/org/openmrs/module/initializer/api/billing/BillableServicesLineProcessor.java
Outdated
Show resolved
Hide resolved
...2.4/src/main/java/org/openmrs/module/initializer/api/billing/ServicePricesLineProcessor.java
Outdated
Show resolved
Hide resolved
...2.4/src/main/java/org/openmrs/module/initializer/api/billing/ServicePricesLineProcessor.java
Outdated
Show resolved
Hide resolved
...src/test/java/org/openmrs/module/initializer/api/BillableServicesLoaderIntergrationTest.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make it work with Validator, this will prove that all is well.
See this as an example (with IDGen) of what's required to be done →
openmrs-module-initializer/validator/pom.xml
Lines 186 to 192 in 3b5a541
<dependency> | |
<groupId>org.openmrs.module</groupId> | |
<artifactId>idgen-api</artifactId> | |
<version>${idgenVersion}</version> | |
<scope>runtime</scope> | |
<type>jar</type> | |
</dependency> |
Then, you should validate that you can make a dry run of a piece of billing config, see → https://github.com/mekomsolutions/openmrs-module-initializer/blob/master/readme/validator.md#how-to-make-a-dry-run
api-2.4/src/main/java/org/openmrs/module/initializer/api/billing/CashPointCsvParser.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ruhanga could you check that all is well with this new domain with the Validator?
public abstract class BillableServicesLoaderIntergrationTest extends DomainBaseModuleContextSensitive_2_3_Test { | ||
|
||
public BillableServicesLoaderIntergrationTest() { | ||
super(); | ||
{ | ||
Module mod = new Module("", "billing", "", "", "", "1.1.0-SNAPSHOT"); | ||
mod.setFile(new File("")); | ||
ModuleFactory.getStartedModulesMap().put(mod.getModuleId(), mod); | ||
} | ||
} | ||
|
||
@Override | ||
public void updateSearchIndex() { | ||
// to prevent Data Filter's 'Illegal Record Access' | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @ODORA0.
Thank you for the PR. We should include some integration tests here. You can refer to this example as a guide.
{ | ||
Concept concept = new Concept(); | ||
concept.setShortName(new ConceptName("Antenatal Services", Locale.ENGLISH)); | ||
concept.setConceptClass(conceptService.getConceptClassByName("Misc")); | ||
concept.setDatatype(conceptService.getConceptDatatypeByName("N/A")); | ||
concept = conceptService.saveConcept(concept); | ||
} | ||
{ | ||
Concept concept = new Concept(); | ||
concept.setShortName(new ConceptName("Orthopedic Services", Locale.ENGLISH)); | ||
concept.setConceptClass(conceptService.getConceptClassByName("Misc")); | ||
concept.setDatatype(conceptService.getConceptDatatypeByName("N/A")); | ||
concept = conceptService.saveConcept(concept); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0 did you need to create new test concepts, why not use some from the various test datasets?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mks-d I am picking this from the CSV.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0 you mean you're showing that loading the CSV will modify those concepts accordingly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mks-d I don't follow, please explain. Which datasets did you mean earlier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Within OpenMRS' Spring tests you don't necessarily need to create concepts, you have access to this bunch if you need concepts.
You can even load and use the following extra dataset shipped with Iniz if you ever needed more:
openmrs-module-initializer/api/src/test/resources/testdata/test-concepts.xml
Lines 7 to 22 in 6449d0b
<concept CONCEPT_ID="5497" UUID="a09ab2c5-878e-4905-b25d-5784167d0216" RETIRED="false" DATE_CREATED="2004-08-12 00:00:00.0" VERSION="0.1" DATE_CHANGED="2006-06-09 14:57:33.0" IS_SET="false" DATATYPE_ID="1" CLASS_ID="1" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5498" UUID="4421da0d-42d0-410d-8ffd-47ec6f155d8f" RETIRED="false" DATE_CREATED="2019-12-11 16:59:47.0" DATE_CHANGED="2019-12-11 16:59:47.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5499" UUID="276c5861-cd46-429f-9665-e067ddeca8e3" RETIRED="false" DATE_CREATED="2019-12-11 16:59:47.0" DATE_CHANGED="2019-12-11 16:59:47.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5500" UUID="401d17f2-6a53-4d9e-8df8-08010a837970" RETIRED="false" DATE_CREATED="2019-12-11 16:59:47.0" DATE_CHANGED="2019-12-11 16:59:47.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5501" UUID="542c18f3-a837-41d4-92e9-be53dc825302" RETIRED="false" DATE_CREATED="2019-12-11 16:59:47.0" DATE_CHANGED="2019-12-11 16:59:47.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5502" UUID="13f62545-d0de-4f7b-a86f-04b91afee2d3" RETIRED="false" DATE_CREATED="2019-12-11 16:59:47.0" DATE_CHANGED="2019-12-11 16:59:47.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5503" UUID="d803e973-1010-4415-8659-c011dec707c0" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" VERSION="1.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="true" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5504" UUID="4280217a-eb93-4e2f-9684-28bed4690e7b" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="1" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5505" UUID="b0b15817-79d6-4c33-b7e9-bfa079d46f5f" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="13" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5506" UUID="7517abe5-8a70-4347-af17-c7e31fa75579" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" VERSION="1.7" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5507" UUID="995ceb0e-d397-4560-bbf1-7642d143a0a2" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5508" UUID="4c93c34e-37c2-11ea-bd28-d70ffe7aa802" RETIRED="true" DATE_CREATED="2019-12-11 16:59:48.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5509" UUID="fda5cc2a-6245-4d91-be17-446d27aab33b" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5510" UUID="4cfe07b0-3061-11ec-8d2b-0242ac110002" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5511" UUID="61214827-303f-11ec-8d2b-0242ac110002" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> | |
<concept CONCEPT_ID="5512" UUID="1ddb8255-00d5-45e8-8830-f9567919a382" RETIRED="false" DATE_CREATED="2019-12-11 16:59:48.0" DATE_CHANGED="2019-12-11 16:59:48.0" IS_SET="false" DATATYPE_ID="3" CLASS_ID="11" CHANGED_BY="1" CREATOR="1"/> |
String uuid = line.getString(HEADER_UUID); | ||
if (StringUtils.isNotBlank(uuid)) { | ||
paymentMode.setUuid(uuid); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the UUID not required (like the name is)?
if (line.containsHeader(HEADER_UUID)) { | ||
String uuid = line.getString(HEADER_UUID); | ||
if (StringUtils.isNotBlank(uuid)) { | ||
cashPoint.setUuid(uuid); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not
cashPoint.setUuid(line.getString(HEADER_UUID));
?
... if the UUID is not required of course.
@Test | ||
public void testBootstrapWithExistingService() { | ||
String uuid = "44ebd6cd-04ad-4eba-8ce1-0de4564bfd17"; | ||
CsvLine csvLine = new CsvLine(new String[] { "Uuid" }, new String[] { uuid }); | ||
|
||
BillableService existingService = new BillableService(); | ||
when(billableServiceResource.getByUniqueId(uuid)).thenReturn(existingService); | ||
|
||
BillableService result = parser.bootstrap(csvLine); | ||
|
||
assertNotNull(result); | ||
assertEquals(existingService, result); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Starting with this one, divide all your test methods/cases as best as can following the given-when-then pattern. Eg.:
Lines 37 to 48 in 6449d0b
@Test | |
public void bootstrap_shouldBootstrapObjectGivenUuidPresentAndObjectNotVoid() { | |
// Setup | |
CsvLine line = new CsvLine(new String[] { "uuid", "void/retire" }, | |
new String[] { "d9e04a9d-d534-4a02-9c40-1c173f3d1d4b", "False" }); | |
// Replay | |
OpenmrsObject obj = displayParser.bootstrap(line); | |
// Verify | |
verify(someParser, times(1)).bootstrap(line); | |
} |
Also the method name follows a convention, see also the example above: bootstrap_shouldBootstrapObjectGivenUuidPresentAndObjectNotVoid
.
As in: "method being tested" + "_" + "expected outcome".
public void setup() { | ||
{ | ||
Concept concept = conceptService.getConceptByUuid("a09ab2c5-878e-4905-b25d-5784167d0216"); | ||
Assert.assertNotNull("Concept should not be null", concept); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this concept is in the test dataset you don't need to assert this, IMO. Also you don't need to craft a special message. If somehow the test dataset is broken, then it's another story, it will be detected and fixed accordingly.
} | ||
{ | ||
Concept concept = conceptService.getConceptByUuid("4421da0d-42d0-410d-8ffd-47ec6f155d8f"); | ||
Assert.assertNotNull("Concept should not be null", concept); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
...4/src/test/java/org/openmrs/module/initializer/api/BillableServiceLoaderIntegrationTest.java
Outdated
Show resolved
Hide resolved
{ | ||
BillableService service = billableServiceResource.getByUniqueId("44ebd6cd-04ad-4eba-8ce1-0de4564bfd17"); | ||
Assert.assertNotNull(service); | ||
Assert.assertEquals(conceptService.getConceptByUuid("a09ab2c5-878e-4905-b25d-5784167d0216"), service.getConcept()); | ||
Assert.assertEquals(BillableServiceStatus.ENABLED, service.getServiceStatus()); | ||
} | ||
{ | ||
BillableService service = billableServiceResource.getByUniqueId("a0f7d8a1-4fa2-418c-aa8a-9b358f43d605"); | ||
Assert.assertNotNull(service); | ||
Assert.assertEquals(conceptService.getConceptByUuid("4421da0d-42d0-410d-8ffd-47ec6f155d8f"), service.getConcept()); | ||
Assert.assertEquals(BillableServiceStatus.ENABLED, service.getServiceStatus()); | ||
} | ||
{ | ||
BillableService service = billableServiceResource.getByUniqueId("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
Assert.assertNotNull(service); | ||
Assert.assertEquals("Updated Service", service.getName()); | ||
Assert.assertEquals(BillableServiceStatus.DISABLED, service.getServiceStatus()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Precedes this with "// verify
":
// verify
...
@Ruhanga Please review |
if (line.containsHeader(HEADER_LOCATION)) { | ||
String location = line.getString(HEADER_LOCATION); | ||
if (StringUtils.isNotBlank(location)) { | ||
cashPoint.setLocation(Utils.fetchLocation(location, locationService)); | ||
} else { | ||
cashPoint.setLocation(null); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure you can't compactify all this into just
String location = line.getString(HEADER_LOCATION);
cashPoint.setLocation(Utils.fetchLocation(location, locationService));
?
Did you check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
@Override | ||
public CashPoint fill(CashPoint cashPoint, CsvLine line) throws IllegalArgumentException { | ||
// UUID is required |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may remove this line is in fact the UUID is not required.
public CashPoint fill(CashPoint cashPoint, CsvLine line) throws IllegalArgumentException { | ||
// UUID is required | ||
cashPoint.setUuid(line.get(HEADER_UUID)); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may remove this empty line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
// Process UUID (required) | ||
String uuid = line.get(HEADER_UUID, true); | ||
if (StringUtils.isNotBlank(uuid)) { | ||
paymentMode.setUuid(uuid); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the UUID required for payment modes but not for cash points?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are actually required, changing that for cash points
protected static final String HEADER_UUID = "uuid"; | ||
|
||
protected static final String HEADER_NAME = "name"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those two are already defined in BaseLineProcessor
, you get them for free.
// Process UUID (required) | ||
paymentMode.setUuid(line.get(HEADER_UUID, true)); | ||
// Process Name (required) | ||
paymentMode.setName(line.get(HEADER_NAME, true)); | ||
// Process other optional attributes | ||
processAttribute(line, HEADER_PRICE, paymentMode); | ||
processAttribute(line, HEADER_PAYMENT_MODE, paymentMode); | ||
processAttribute(line, HEADER_ITEM, paymentMode); | ||
processAttribute(line, HEADER_BILLABLE_SERVICE, paymentMode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need to document in the code which is optional and which is not, this is done in the READMEs and should be self-explanatory through the use of the throwable version or not.
So let's get rid of the comments, you didn't set them in CashPointsLineProcessor
anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for adding tests, @ODORA0. Moving forward, you'll add more integration tests for each of the newly introduced domain loaders. Currently, we only have one, BillableServiceLoaderIntegrationTest
. Here are a few other specific points to address:
api-2.4/pom.xml
Outdated
<dependency> | ||
<groupId>org.openmrs.module</groupId> | ||
<artifactId>billing-omod</artifactId> | ||
<version>${billingVersion}</version> | ||
<scope>provided</scope> | ||
</dependency> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0, we should rather depend on the sub-modules' api packages than the omod web api package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ruhanga Please advise, given the constraint that BillableServiceResource
is only available in the billing-omod module and not in the billing-api module, transitioning to use billing-api will limit the direct operations we can perform on BillableService entities since these operations are currently done through the BillableServiceResource.
Also are you suggesting adding integration tests for all the other domain in this PR as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0 Iniz doesn't need any REST resources, it only needs the Java API of the modules it depends on. You can indeed switch to depending on the -api
submodule and, if all your Spring tests pass, you're good.
Also are you suggesting adding integration tests for all the other domain in this PR as well?
Yes indeed. You need to bring as a test resource a typical, real-world looking, CSV file and demonstrate through your tests that the outcome of loading each CSV file is as expected and can be asserted.
Each *Loader
class should have its corresponding Spring test (context sensitive) class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One other obvious observation...
BillableService service = billableServiceResource.getByUniqueId("44ebd6cd-04ad-4eba-8ce1-0de4564bfd17"); | ||
Assert.assertNotNull(service); | ||
Assert.assertEquals(conceptService.getConceptByUuid("a09ab2c5-878e-4905-b25d-5784167d0216"), service.getConcept()); | ||
Assert.assertEquals(BillableServiceStatus.ENABLED, service.getServiceStatus()); | ||
} | ||
{ | ||
BillableService service = billableServiceResource.getByUniqueId("a0f7d8a1-4fa2-418c-aa8a-9b358f43d605"); | ||
Assert.assertNotNull(service); | ||
Assert.assertEquals(conceptService.getConceptByUuid("4421da0d-42d0-410d-8ffd-47ec6f155d8f"), service.getConcept()); | ||
Assert.assertEquals(BillableServiceStatus.ENABLED, service.getServiceStatus()); | ||
} | ||
{ | ||
BillableService service = billableServiceResource.getByUniqueId("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
Assert.assertNotNull(service); | ||
Assert.assertEquals("Updated Service", service.getName()); | ||
Assert.assertEquals(BillableServiceStatus.DISABLED, service.getServiceStatus()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is actually testing the loading of the billable services csv file located at resources/testAppDataDir/configuration/billableservices/services.csv
since what's being retrieved is what's being saved inside setup()
above. Else you'd have to remove setup()
altogether or use it to save billable services to be edited or voided by contents of services.csv
, which are valid update use-cases to test.
api-2.4/pom.xml
Outdated
<dependency> | ||
<groupId>org.openmrs.module</groupId> | ||
<artifactId>billing-omod</artifactId> | ||
<version>${billingVersion}</version> | ||
<scope>provided</scope> | ||
</dependency> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0 Iniz doesn't need any REST resources, it only needs the Java API of the modules it depends on. You can indeed switch to depending on the -api
submodule and, if all your Spring tests pass, you're good.
Also are you suggesting adding integration tests for all the other domain in this PR as well?
Yes indeed. You need to bring as a test resource a typical, real-world looking, CSV file and demonstrate through your tests that the outcome of loading each CSV file is as expected and can be asserted.
Each *Loader
class should have its corresponding Spring test (context sensitive) class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, @ODORA0, for contributing additional tests. For all loader integration tests, our goals should encompass at least three verifications: 1.) Creating entities, 2.) Modifying existing entities, and 3.) Retiring/un-retiring of existing entities via CSV lines. You can refer to this example here for guidance.
PaymentMode paymentMode = paymentModeService.getByUuid("526bf278-ba81-4436-b867-c2f6641d060a"); | ||
assertNotNull(paymentMode); | ||
assertEquals("Cash", paymentMode.getName()); | ||
assertEquals("Cash payment mode", paymentMode.getDescription()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't validate that the csv file configuration/billableserviceprices/ServicePrices.csv
was loaded. Validation would be fine if what's in setup()
of this same file was removed.
CashPoint cashPoint = iCashPointService.getByUuid("54065383-b4d4-42d2-af4d-d250a1fd2590"); | ||
assertNotNull(cashPoint); | ||
assertEquals("OPD Cash Point", cashPoint.getName()); | ||
assertEquals("Opd cash point for billing", cashPoint.getDescription()); | ||
|
||
Location location = locationService.getLocationByUuid("8d6c7b96-29de-102b-86b0-7a5022ba4115"); | ||
assertEquals(location, cashPoint.getLocation()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't validate that the csv file configuration/billableserviceprices/cashPoints.csv
was loaded. Validation would be fine if what's in setup()
of this same file was removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0, please remember to provide separate dedicated README documentation for each of the added domains. This should include definitions for all the domain specific fields (See this example).
Additionally, update the existing documentation as highlighted below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For all loader integration tests, our goals should encompass at least three verifications: 1.) Creating entities, 2.) Modifying existing entities, and 3.) Retiring/un-retiring of existing entities via CSV lines. You can refer to this example here for guidance.
Thanks for the changes @ODORA0. Let's remember to address the above comment too.
426bfe4
to
849e318
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0 could you please push the changes without using force push for now? It complicates the review process, especially when some comments need to be properly resolved.
@@ -0,0 +1,2 @@ | |||
uuid, name, price, paymentMode, item, billableService | |||
526bf278-ba81-4436-b867-c2f6641d060a, Antenatal Cash Item, 10000, Cash, , Antenatal Care |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One line is insufficient to validate at least three scenarios: creation, editing, and retirement.
@@ -0,0 +1,2 @@ | |||
uuid,name,description,location | |||
54065383-b4d4-42d2-af4d-d250a1fd2590, OPD Cash Point, Opd cash point for billing, ART Clinic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0 overall, this looks good. Let's refine a few details below.
import org.openmrs.module.initializer.api.CsvParser; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
@OpenmrsProfile(modules = { "billing:1.1.0" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@OpenmrsProfile(modules = { "billing:1.1.0" }) | |
@OpenmrsProfile(modules = { "billing:1.1.0 - 9.*" }) |
import org.openmrs.module.initializer.api.loaders.BaseCsvLoader; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
@OpenmrsProfile(modules = { "billing:1.1.0" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here...
/** | ||
* This is the first level line processor for Billable Services | ||
*/ | ||
@OpenmrsProfile(modules = { "billing:1.1.0" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Qualifier; | ||
|
||
@OpenmrsProfile(modules = { "billing:1.1.0" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
import org.openmrs.module.initializer.api.loaders.BaseCsvLoader; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
@OpenmrsProfile(modules = { "billing:1.1.0" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Qualifier; | ||
|
||
@OpenmrsProfile(modules = { "billing:1.1.0" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Qualifier; | ||
|
||
@OpenmrsProfile(modules = { "billing:1.1.0" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
import org.openmrs.module.initializer.api.loaders.BaseCsvLoader; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
@OpenmrsProfile(modules = { "billing:1.1.0" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
BillableService service = billableItemsService.getByUuid("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
service.setName("Nutrition counseling updated"); | ||
service.setServiceStatus(BillableServiceStatus.DISABLED); | ||
billableItemsService.save(service); | ||
|
||
loader.load(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be done through the setup and loader.loader()
run once above on line 30. The same is true for the other test cases including those in other domain loader tests.
// Retire and un-retire an existing entity via CSV (assuming retirement is done by setting status to DISABLED) | ||
{ | ||
BillableService service = billableItemsService.getByUuid("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
service.setServiceStatus(BillableServiceStatus.DISABLED); | ||
billableItemsService.save(service); | ||
|
||
loader.load(); | ||
|
||
BillableService retiredService = billableItemsService.getByUuid("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
Assert.assertEquals(BillableServiceStatus.DISABLED, retiredService.getServiceStatus()); | ||
|
||
retiredService.setServiceStatus(BillableServiceStatus.ENABLED); | ||
billableItemsService.save(retiredService); | ||
|
||
loader.load(); | ||
|
||
BillableService unretiredService = billableItemsService.getByUuid("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
Assert.assertEquals(BillableServiceStatus.ENABLED, unretiredService.getServiceStatus()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should assert that retiredService.getRetired() == true
, the same is true for similar test cases on the other domains.
public void setup() throws Exception { | ||
executeDataSet("testdata/test-metadata.xml"); | ||
loader.load(); | ||
} | ||
|
||
@Test | ||
public void shouldCreateCashPointsFromCSV() { | ||
// Verify creation for all CashPoints | ||
CashPoint cashPoint1 = iCashPointService.getByUuid("54065383-b4d4-42d2-af4d-d250a1fd2590"); | ||
assertNotNull(cashPoint1); | ||
assertEquals("OPD Cash Point", cashPoint1.getName()); | ||
assertEquals("Opd cash point for billing", cashPoint1.getDescription()); | ||
|
||
Location location1 = locationService.getLocation("ART Clinic"); | ||
assertNotNull(location1); | ||
assertEquals("ART Clinic", location1.getName()); | ||
assertEquals(location1, cashPoint1.getLocation()); | ||
|
||
CashPoint cashPoint2 = iCashPointService.getByUuid("c56a108f-e3c5-4881-a5e8-a796601883b9"); | ||
assertNotNull(cashPoint2); | ||
assertEquals("IPD Cash Point", cashPoint2.getName()); | ||
assertEquals("IPD cash point for billing", cashPoint2.getDescription()); | ||
|
||
Location location2 = locationService.getLocation("Inpatient Ward"); | ||
assertNotNull(location2); | ||
assertEquals("Inpatient Ward", location2.getName()); | ||
assertEquals(location2, cashPoint2.getLocation()); | ||
|
||
CashPoint cashPoint3 = iCashPointService.getByUuid("8e48e0be-1a31-4bd3-a54d-ace82653f8b8"); | ||
assertNotNull(cashPoint3); | ||
assertEquals("MCH Cash Point", cashPoint3.getName()); | ||
assertEquals("MCH cash point for billing", cashPoint3.getDescription()); | ||
|
||
Location location3 = locationService.getLocation("MCH Clinic"); | ||
assertNotNull(location3); | ||
assertEquals("MCH Clinic", location3.getName()); | ||
assertEquals(location3, cashPoint3.getLocation()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kind of change I was expecting seen on all the loader integration tests @ODORA0.
public void setup() throws Exception { | |
executeDataSet("testdata/test-metadata.xml"); | |
loader.load(); | |
} | |
@Test | |
public void shouldCreateCashPointsFromCSV() { | |
// Verify creation for all CashPoints | |
CashPoint cashPoint1 = iCashPointService.getByUuid("54065383-b4d4-42d2-af4d-d250a1fd2590"); | |
assertNotNull(cashPoint1); | |
assertEquals("OPD Cash Point", cashPoint1.getName()); | |
assertEquals("Opd cash point for billing", cashPoint1.getDescription()); | |
Location location1 = locationService.getLocation("ART Clinic"); | |
assertNotNull(location1); | |
assertEquals("ART Clinic", location1.getName()); | |
assertEquals(location1, cashPoint1.getLocation()); | |
CashPoint cashPoint2 = iCashPointService.getByUuid("c56a108f-e3c5-4881-a5e8-a796601883b9"); | |
assertNotNull(cashPoint2); | |
assertEquals("IPD Cash Point", cashPoint2.getName()); | |
assertEquals("IPD cash point for billing", cashPoint2.getDescription()); | |
Location location2 = locationService.getLocation("Inpatient Ward"); | |
assertNotNull(location2); | |
assertEquals("Inpatient Ward", location2.getName()); | |
assertEquals(location2, cashPoint2.getLocation()); | |
CashPoint cashPoint3 = iCashPointService.getByUuid("8e48e0be-1a31-4bd3-a54d-ace82653f8b8"); | |
assertNotNull(cashPoint3); | |
assertEquals("MCH Cash Point", cashPoint3.getName()); | |
assertEquals("MCH cash point for billing", cashPoint3.getDescription()); | |
Location location3 = locationService.getLocation("MCH Clinic"); | |
assertNotNull(location3); | |
assertEquals("MCH Clinic", location3.getName()); | |
assertEquals(location3, cashPoint3.getLocation()); | |
} | |
public void setup() throws Exception { | |
executeDataSet("testdata/test-metadata.xml"); | |
} | |
@Test | |
public void shouldCreateCashPointsFromCSV() { | |
// Replay | |
loader.load(); | |
// Verify creation for all CashPoints | |
CashPoint cashPoint1 = iCashPointService.getByUuid("54065383-b4d4-42d2-af4d-d250a1fd2590"); | |
assertNotNull(cashPoint1); | |
assertEquals("OPD Cash Point", cashPoint1.getName()); | |
assertEquals("Opd cash point for billing", cashPoint1.getDescription()); | |
Location location1 = locationService.getLocation("ART Clinic"); | |
assertNotNull(location1); | |
assertEquals("ART Clinic", location1.getName()); | |
assertEquals(location1, cashPoint1.getLocation()); | |
CashPoint cashPoint2 = iCashPointService.getByUuid("c56a108f-e3c5-4881-a5e8-a796601883b9"); | |
assertNotNull(cashPoint2); | |
assertEquals("IPD Cash Point", cashPoint2.getName()); | |
assertEquals("IPD cash point for billing", cashPoint2.getDescription()); | |
Location location2 = locationService.getLocation("Inpatient Ward"); | |
assertNotNull(location2); | |
assertEquals("Inpatient Ward", location2.getName()); | |
assertEquals(location2, cashPoint2.getLocation()); | |
CashPoint cashPoint3 = iCashPointService.getByUuid("8e48e0be-1a31-4bd3-a54d-ace82653f8b8"); | |
assertNotNull(cashPoint3); | |
assertEquals("MCH Cash Point", cashPoint3.getName()); | |
assertEquals("MCH cash point for billing", cashPoint3.getDescription()); | |
Location location3 = locationService.getLocation("MCH Clinic"); | |
assertNotNull(location3); | |
assertEquals("MCH Clinic", location3.getName()); | |
assertEquals(location3, cashPoint3.getLocation()); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few outstanding issues need to be addressed @ODORA0. Let’s try to make sure to implement proper assertions as recommended below.
BillableService service = billableItemsService.getByUuid("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
service.setName("Nutrition counseling updated"); | ||
service.setServiceStatus(BillableServiceStatus.DISABLED); | ||
billableItemsService.save(service); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be accomplished by a .csv
line corresponding to a pre-existing record, likely saved during the setup()
method. When loader.load()
is called, the existing record should be updated with the relevant line from the .csv
file. After that, you can verify that the .csv
line was loaded correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Ruhanga Please expound on this, I don't follow
BillableService service = billableItemsService.getByUuid("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
service.setServiceStatus(BillableServiceStatus.DISABLED); | ||
billableItemsService.save(service); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here for retiring.
// Unretire the entity | ||
retiredService.setServiceStatus(BillableServiceStatus.ENABLED); | ||
billableItemsService.save(retiredService); | ||
|
||
BillableService unretiredService = billableItemsService.getByUuid("16435ab4-27c3-4d91-b21e-52819bd654d8"); | ||
Assert.assertEquals(BillableServiceStatus.ENABLED, unretiredService.getServiceStatus()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here...
// Modify an existing entity in the CSV | ||
CashPoint cashPoint = iCashPointService.getByUuid("54065383-b4d4-42d2-af4d-d250a1fd2590"); | ||
cashPoint.setName("OPD Cash Point Updated"); | ||
iCashPointService.save(cashPoint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here...
// Retire an existing entity in the CSV | ||
CashPoint cashPoint = iCashPointService.getByUuid("c56a108f-e3c5-4881-a5e8-a796601883b9"); | ||
cashPoint.setRetired(true); | ||
iCashPointService.save(cashPoint); | ||
|
||
CashPoint retiredCashPoint = iCashPointService.getByUuid("c56a108f-e3c5-4881-a5e8-a796601883b9"); | ||
assertTrue(retiredCashPoint.getRetired()); | ||
|
||
// Unretire the entity | ||
retiredCashPoint.setRetired(false); | ||
iCashPointService.save(retiredCashPoint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here for retiring and un-retiring
// Modify an existing entity in the CSV | ||
PaymentMode paymentMode = paymentModeService.getByUuid("526bf278-ba81-4436-b867-c2f6641d060a"); | ||
paymentMode.setName("Cash Updated"); | ||
paymentModeService.save(paymentMode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here...
// Retire an existing entity in the CSV | ||
PaymentMode paymentMode = paymentModeService.getByUuid("2b1b9aae-5d35-43dd-9214-3fd370fd7737"); | ||
paymentMode.setRetired(true); | ||
paymentModeService.save(paymentMode); | ||
|
||
PaymentMode retiredPaymentMode = paymentModeService.getByUuid("2b1b9aae-5d35-43dd-9214-3fd370fd7737"); | ||
Assert.assertTrue(retiredPaymentMode.getRetired()); | ||
|
||
// Unretire the entity | ||
retiredPaymentMode.setRetired(false); | ||
paymentModeService.save(retiredPaymentMode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here for retiring and un-retiring...
@ODORA0 do the tests you added run successfully when you run |
eedf490
to
8a629ab
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ODORA0, I’ve successfully set up an appropriate test environment and resolved the issues with the Billable Services Domain integration tests. Could you take it from here and proceed with the other domain tests, using the Billable Services Domain integration tests as a reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left few comments.
Generally LGTM. I'll let @Ruhanga have final say in this one.
api-2.4/src/test/java/org/openmrs/module/initializer/api/BillableServiceCsvParserTest.java
Outdated
Show resolved
Hide resolved
api-2.4/src/test/java/org/openmrs/module/initializer/api/CashPointLoaderIntegrationTest.java
Outdated
Show resolved
Hide resolved
...2.4/src/test/java/org/openmrs/module/initializer/api/ServicePricesLoaderIntegrationTest.java
Outdated
Show resolved
Hide resolved
...2.4/src/test/java/org/openmrs/module/initializer/api/ServicePricesLoaderIntegrationTest.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally LGTM!
/** | ||
* This is the first level line processor for Billable Services | ||
*/ | ||
@OpenmrsProfile(modules = { "billing:1.1.0 - 9.*" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s quite restrictive to specify version 1.1.0
as the required version. We would prefer to set 1.1.0
as the minimum version instead. Version 9.*
provides a more flexible range for usage, accommodating future updates until potential incompatibility issues arise.
This PR takes care of adding the OpenMRS Billing Module domains to iniz
BILLABLE_SERVICES
that represents services that can be billed within the billing module with attributes such as the name, short name, concept, service type, service category, service prices, and service status, handling creation of billable services in the billing module e.g. Covid Vaccination Service that might be a billable service in a facility under the Vaccination Services, Ultra Sound Scanning Services under the Antenatal Services, Complete Blood Count that can be under Clinical Consultation Services etc.CASH_POINTS
which represents a locations such as OPD Clinic, ART Clinic within the OpenMRS billing module where bills can be created and paidBILLABLE_SERVICE_PRICES
which are payment modes that represents different modes of payment (such as cash, mobile money or credit card) within the billing module which also allows for customisable attribute types, enabling users to define additional properties for each payment mode like the pricing of the different payments