Skip to content
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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ configuration/
├── attributetypes/
├── autogenerationoptions/
├── bahmniforms/
├── billing/
├── cohorttypes/
├── cohortattributetypes/
├── conceptclasses/
Expand Down Expand Up @@ -127,6 +128,7 @@ This is the list of currently supported domains in their loading order:
1. [Concept Sources (CSV files)](readme/conceptsources.md)
1. [Open Concept Lab (ZIP Files)](readme/ocl.md)
1. [Concepts (CSV files)](readme/concepts.md)
1. [Billing (CSV files)](readme/billing.md)
1. [Concept Sets and Answers (CSV files)](readme/conceptsets.md)
1. [Programs (CSV files)](readme/prog.md)
1. [Program Worklows (CSV files)](readme/prog.md)
Expand Down Expand Up @@ -166,6 +168,7 @@ mvn clean package
* Bahmni Appointments 1.2.1 (*compatible*)
* Bahmni Core 0.93 (*compatible*)
* Bahmni I.e Apps 1.1.0 (*compatible*)
* Billing 1.1.0 (*compatible*)
* Data Filter 1.0.0 (*compatible*)
* HTML Form Entry 4.0.0 (*compatible*)
* ID Gen 4.3 (*compatible*)
Expand Down Expand Up @@ -196,6 +199,7 @@ See the [documentation on Initializer's logging properties](readme/rtprops.md#lo

#### Version 2.7.0
* Added support for 'queues' domain.
* Added support for 'billing' domain.
* Added support for 'addresshierarchy' domain.
* Fix for Liquibase Loader to ensure compatibility with OpenMRS versions 2.5.5+.
* Fix for OCL Loader to ensure it throws an Exception if the OCL import fails.
Expand Down
8 changes: 8 additions & 0 deletions api-2.4/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

<properties>
<openmrsPlatformVersion>${openmrsVersion2.4}</openmrsPlatformVersion>
<billingVersion>1.1.0</billingVersion>
</properties>

<dependencies>
Expand Down Expand Up @@ -63,6 +64,13 @@
<scope>test</scope>
<type>test-jar</type>
</dependency>

<dependency>
<groupId>org.openmrs.module</groupId>
<artifactId>billing-omod</artifactId>
<version>${billingVersion}</version>
<scope>provided</scope>
</dependency>
Comment on lines +68 to +73
Copy link
Member

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.

Copy link
Author

@ODORA0 ODORA0 Jul 4, 2024

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?

Copy link
Member

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.

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.openmrs.module.initializer.api.billing;

import org.apache.commons.lang3.StringUtils;
import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.module.billing.api.model.BillableService;
import org.openmrs.module.billing.web.rest.resource.BillableServiceResource;
import org.openmrs.module.initializer.Domain;
import org.openmrs.module.initializer.api.BaseLineProcessor;
import org.openmrs.module.initializer.api.CsvLine;
import org.openmrs.module.initializer.api.CsvParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@OpenmrsProfile(modules = { "billing:1.1.0" })
public class BillableServiceCsvParser extends CsvParser<BillableService, BaseLineProcessor<BillableService>> {

private final BillableServiceResource billableServiceResource;

@Autowired
public BillableServiceCsvParser(
@Qualifier("billableService.billableServiceResource") BillableServiceResource billableServiceResource,
BillableServicesLineProcessor processor) {
super(processor);
this.billableServiceResource = billableServiceResource;
}

@Override
public Domain getDomain() {
return Domain.BILLABLE_SERVICES;
}

@Override
public BillableService bootstrap(CsvLine line) throws IllegalArgumentException {
String uuid = line.getUuid();
BillableService billableService = billableServiceResource.getByUniqueId(uuid);
if (billableService == null) {
billableService = new BillableService();
}
if (StringUtils.isNotBlank(uuid)) {
billableService.setUuid(uuid);
}
return billableService;
}

@Override
public BillableService save(BillableService instance) {
return billableServiceResource.save(instance);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.openmrs.module.initializer.api.billing;

import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.module.billing.api.model.BillableService;
import org.openmrs.module.initializer.api.loaders.BaseCsvLoader;
import org.springframework.beans.factory.annotation.Autowired;

@OpenmrsProfile(modules = { "billing:1.1.0" })
public class BillableServiceLoader extends BaseCsvLoader<BillableService, BillableServiceCsvParser> {

@Autowired
public void setParser(BillableServiceCsvParser parser) {
this.parser = parser;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.openmrs.module.initializer.api.billing;

import org.apache.commons.lang3.StringUtils;
import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.api.ConceptService;
import org.openmrs.module.billing.api.model.BillableService;
import org.openmrs.module.billing.api.model.BillableServiceStatus;
import org.openmrs.module.initializer.api.BaseLineProcessor;
import org.openmrs.module.initializer.api.CsvLine;
import org.openmrs.module.initializer.api.utils.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
* This is the first level line processor for Billable Services
*/
@OpenmrsProfile(modules = { "billing:1.1.0" })
public class BillableServicesLineProcessor extends BaseLineProcessor<BillableService> {

protected static final String HEADER_NAME = "service name";

protected static final String HEADER_DESC = "short name";

protected static final String HEADER_SERVICE = "concept";

protected static final String HEADER_SERVICE_TYPE = "service type";

protected static final String HEADER_SERVICE_STATUS = "service status";

private final ConceptService conceptService;

@Autowired
public BillableServicesLineProcessor(@Qualifier("conceptService") ConceptService conceptService) {
super();
this.conceptService = conceptService;
}

@Override
public BillableService fill(BillableService billableService, CsvLine line) throws IllegalArgumentException {
billableService.setName(line.get(HEADER_NAME, true));
billableService.setShortName(line.getString(HEADER_DESC));

String service = line.getString(HEADER_SERVICE);
billableService.setConcept(Utils.fetchConcept(service, conceptService));

String serviceType = line.getString(HEADER_SERVICE_TYPE);
billableService.setServiceType(Utils.fetchConcept(serviceType, conceptService));

String serviceStatus = line.getString(HEADER_SERVICE_STATUS);
billableService.setServiceStatus(
StringUtils.isNotBlank(serviceStatus) ? BillableServiceStatus.valueOf(serviceStatus.toUpperCase())
: BillableServiceStatus.ENABLED);

return billableService;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.openmrs.module.initializer.api.billing;

import org.apache.commons.lang3.StringUtils;
import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.module.billing.api.ICashPointService;
import org.openmrs.module.billing.api.model.CashPoint;
import org.openmrs.module.initializer.Domain;
import org.openmrs.module.initializer.api.BaseLineProcessor;
import org.openmrs.module.initializer.api.CsvLine;
import org.openmrs.module.initializer.api.CsvParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@OpenmrsProfile(modules = { "billing:1.1.0" })
public class CashPointCsvParser extends CsvParser<CashPoint, BaseLineProcessor<CashPoint>> {
mks-d marked this conversation as resolved.
Show resolved Hide resolved

private final ICashPointService iCashPointService;

@Autowired
public CashPointCsvParser(@Qualifier("iCashPointService") ICashPointService iCashPointService,
CashPointsLineProcessor processor) {
super(processor);
this.iCashPointService = iCashPointService;
}

@Override
public Domain getDomain() {
return Domain.CASH_POINTS;
}

@Override
public CashPoint bootstrap(CsvLine line) throws IllegalArgumentException {
String uuid = line.getUuid();
CashPoint cashPoint = null;
if (StringUtils.isNotBlank(uuid)) {
cashPoint = iCashPointService.getByUuid(uuid);
}
if (cashPoint == null) {
cashPoint = new CashPoint();
if (StringUtils.isNotBlank(uuid)) {
cashPoint.setUuid(uuid);
}
}
return cashPoint;
}

@Override
public CashPoint save(CashPoint instance) {
return iCashPointService.save(instance);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.openmrs.module.initializer.api.billing;

import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.module.billing.api.model.CashPoint;
import org.openmrs.module.initializer.api.loaders.BaseCsvLoader;
import org.springframework.beans.factory.annotation.Autowired;

@OpenmrsProfile(modules = { "billing:1.1.0" })
public class CashPointLoader extends BaseCsvLoader<CashPoint, CashPointCsvParser> {
mks-d marked this conversation as resolved.
Show resolved Hide resolved

@Autowired
public void setParser(CashPointCsvParser parser) {
this.parser = parser;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.openmrs.module.initializer.api.billing;

import org.apache.commons.lang3.StringUtils;
import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.api.LocationService;
import org.openmrs.module.billing.api.model.CashPoint;
import org.openmrs.module.initializer.api.BaseLineProcessor;
import org.openmrs.module.initializer.api.CsvLine;
import org.openmrs.module.initializer.api.utils.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@OpenmrsProfile(modules = { "billing:1.1.0" })
public class CashPointsLineProcessor extends BaseLineProcessor<CashPoint> {

protected static final String HEADER_UUID = "uuid";

protected static final String HEADER_NAME = "name";

protected static final String HEADER_DESCRIPTION = "description";

protected static final String HEADER_LOCATION = "location";

private final LocationService locationService;

@Autowired
public CashPointsLineProcessor(@Qualifier("locationService") LocationService locationService) {
super();
this.locationService = locationService;
}

@Override
public CashPoint fill(CashPoint cashPoint, CsvLine line) throws IllegalArgumentException {
cashPoint.setUuid(line.get(HEADER_UUID, true));
cashPoint.setName(line.get(HEADER_NAME, true));
cashPoint.setDescription(line.getString(HEADER_DESCRIPTION));
String location = line.getString(HEADER_LOCATION);
cashPoint.setLocation(Utils.fetchLocation(location, locationService));

return cashPoint;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.openmrs.module.initializer.api.billing;

import org.apache.commons.lang3.StringUtils;
import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.module.billing.api.IPaymentModeService;
import org.openmrs.module.billing.api.model.PaymentMode;
import org.openmrs.module.initializer.Domain;
import org.openmrs.module.initializer.api.BaseLineProcessor;
import org.openmrs.module.initializer.api.CsvLine;
import org.openmrs.module.initializer.api.CsvParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@OpenmrsProfile(modules = { "billing:1.1.0" })
public class ServicePricesCsvParser extends CsvParser<PaymentMode, BaseLineProcessor<PaymentMode>> {

private final IPaymentModeService paymentModeService;

@Autowired
public ServicePricesCsvParser(@Qualifier("paymentModeService") IPaymentModeService paymentModeService,
ServicePricesLineProcessor processor) {
super(processor);
this.paymentModeService = paymentModeService;
}

@Override
public Domain getDomain() {
return Domain.BILLABLE_SERVICE_PRICES;
}

@Override
public PaymentMode bootstrap(CsvLine line) throws IllegalArgumentException {
String uuid = line.getUuid();
PaymentMode paymentMode = paymentModeService.getByUuid(uuid);
if (paymentMode == null) {
paymentMode = new PaymentMode();
if (StringUtils.isNotBlank(uuid)) {
paymentMode.setUuid(uuid);
}
}
return paymentMode;
}

@Override
public PaymentMode save(PaymentMode instance) {
return paymentModeService.save(instance);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.openmrs.module.initializer.api.billing;

import org.apache.commons.lang3.StringUtils;
import org.openmrs.annotation.OpenmrsProfile;
import org.openmrs.api.ConceptService;
import org.openmrs.module.billing.api.model.PaymentMode;
import org.openmrs.module.initializer.api.BaseLineProcessor;
import org.openmrs.module.initializer.api.CsvLine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

@OpenmrsProfile(modules = { "billing:1.1.0" })
public class ServicePricesLineProcessor extends BaseLineProcessor<PaymentMode> {

protected static final String HEADER_UUID = "uuid";

protected static final String HEADER_NAME = "name";
Comment on lines +15 to +17
Copy link
Member

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.


protected static final String HEADER_PRICE = "price";

protected static final String HEADER_PAYMENT_MODE = "paymentMode";

protected static final String HEADER_ITEM = "item";

protected static final String HEADER_BILLABLE_SERVICE = "billableService";

private final ConceptService conceptService;

@Autowired
public ServicePricesLineProcessor(@Qualifier("conceptService") ConceptService conceptService) {
super();
this.conceptService = conceptService;
}

@Override
public PaymentMode fill(PaymentMode paymentMode, CsvLine line) throws IllegalArgumentException {
// 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);
Comment on lines +37 to +45
Copy link
Member

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.


return paymentMode;
}

private void processAttribute(CsvLine line, String header, PaymentMode paymentMode) {
String value = line.getString(header);
if (StringUtils.isNotBlank(value)) {
paymentMode.addAttributeType(header, "String", null, false);
}
}
}
Loading