How to pass double variable from service into controller - spring

I will provide here a better back story so you can understand a problem.
I have a user, user can have a wallet, now when I list on page all wallets from user, he can click on button to create a new transaction for any wallet. Also, on that page I have field that show me a total net worth of user, that is actually sum of all wallets balance. And that works fine. Now , user can create a transaction without any problem, but problem is updating a net worth on page, so obviously when user add transaction and for example if his net worth is 500 but user created a transaction for 100, his net worth should be updated to 400.
This is thymeleaf how I show total net worth for user;
<div class="header" th:each="wallets : ${wallets}">
<h1>Net Worth</h1>
<h1 th:text="${wallets.totalBalance}"></h1>
</div>
Nothing special, and this is method and controller:
#Override
public Wallet netWorth(Long userId) {
Wallet wallet = new Wallet();
List<Wallet> wallets = walletRepository.findDistinctIdByUserId(userId);
double worth = 0;
for (int i = 0; i < wallets.size(); i++)
worth += wallets.get(i).getInitialBalance();
wallet.setTotalBalance(worth);
return wallet;
}
So basically I go thought all user wallets in for loop and sum each balance and then set that result on field.
This is controller and model that I use on thymeleaf to show wallets that logged user have and also his net worth as I explained before.
#GetMapping("/userWallet/balance/{user_id}")
public String getUserWallet(#PathVariable(value = "user_id") Long user_id, Model model) {
model.addAttribute("wallet", walletService.findDistinctIdByUserId(user_id));
model.addAttribute("wallets", walletService.netWorth(user_id));
return "user_profile";
}
Now is main problem:
I have a service that works fine:
#Override
public double netWorthAfterOutcomeTransaction(Long userId, double amount) {
List<Wallet> wallets = walletRepository.findDistinctIdByUserId(userId);
Wallet wallet = new Wallet();
double worth = 0;
double worthAfterOutcome = 0;
for (int i = 0; i < wallets.size(); i++)
worth += wallets.get(i).getInitialBalance();
worthAfterOutcome = worth - amount;
wallet.setTotalBalance(worthAfterOutcome);
logger.info("Amount entered is: " + amount);
logger.info("Balance after outcome is : " + wallet.getTotalBalance());
return worthAfterOutcome;
}
On loggers that I added new balance after transaction is good, for example if user balance is 4000 and I on form set amount 300 logger will provide next info:
Amount entered is: 300.0
Balance after outcome is : 3700.0
So total balance for all wallets or net worth is updated fine, I have a trouble just to show that new result in thymyleaf. I tried like this:
model.addAttribute("wallets", transactionService.netWorthAfterOutcomeTransaction(user_id,);
But I have problem to pass double amount in that model

Related

Spring Pagination and count query

I'm developping a REST API managing Module objects. For the UI, I need pagination and the total number of pages.
I know when Spring uses Page<T> an additional count query is used (to get the total number of pages) which is an overhead cost.
I need this total number of pages for the UI. But only once (no need to execute again the count query for each new page).
So I was thinking of exposing two endpoints :
getting the total number of elements
getting the data (so I'm returning a List<Module> instead of Page<Module> because I don't want to execute this extra count query for each page request)
Something like this :
#RestController
#RequestMapping("/api/modules")
public class ModuleApi {
private final ModuleService service;
#GetMapping("/count")
public Long count() {
return service.countModules();
}
#GetMapping
public List<Module> find(
#RequestParam("name") String name ,
#RequestParam(value = "page", required = false, defaultValue = "0") Integer page,
#RequestParam(value = "size", required = false, defaultValue = "10") Integer size
) {
return service.find(PageRequest.of(page, size));
}
}
Is this a good design ?
Counting once means your count will get outdated as more Modules are inserted into your database in which case the count is no longer relevant.
The better design would be to work with spring's Slice<Module>, forget the count altogether, and implement the solution on the front end side. Think of how some sites only fetch you more results when you are at the bottom of the page.
However this may cost a lot of effort and time on your architecture so your proposal should be fine.

Spring Reactor - consuming Pageable endpoint

It's my first time working with Spring Reactor and I've faced the following challenge:
I have a service which allows to consume a number of records specified by page number and page size:
Mono<GetContactsForGroupResponse> getContactsForGroup(Integer page, Integer size);
Among other fields GetContactsForGroupResponse contains pagination metadata:
class GetContactsForGroupResponse {
private int totalPages;
private int totalElements;
private int numberOfElements;
private int size;
private int number;
private boolean first;
private boolean last;
//.....
}
Now I need to write another method that would read all of the pages from
Mono<GetContactsForGroupResponse> getContactsForGroup(Integer page, Integer size);
and combine results into one single collection:
Mono<Collection<GetContactsForGroupResponse>> getContactsForGroup();
So far I've written:
List<GetContactsForGroupResponse> groupContacts = new ArrayList<>();
AtomicBoolean allPagesConsumed = new AtomicBoolean(false);
int pageNumber = 0;
int pageSize = 10;
while(!allPagesConsumed.get()) {
allPagesConsumed.set(true);
GetContactsForGroupResponse getContactsForGroupResponse =
getContactsForGroup(accountId, g.getId(), 0, pageSize).block();
Optional.ofNullable(getContactsForGroupResponse)
.ifPresent(r -> {
allPagesConsumed.set(r.isLast());
groupContacts.add(r);
});
pageNumber ++;
I read results page by page until I reach the last page.
I wonder what is the right way of implementation from SpringReactor point of view
Any advice would be appreciated,
Thanks
there is no "right way", because this not a reactive question.
Since you are fetching "pages" you are dealing with a non reactive way of handling data. You have not disclosed anything about how you fetch this data, and from what type of database.
The easiest thing is to just make a query to the database and fetch everything in one go.
write a getAllContactsForGroup instead, and don't, do a while loop.

Check if current user is a member of exchange distribution list - Outlook C#

I want to find out if current Outlook user is a member of particular exchange distribution list. If he is, then he should see child form and if he isn't; then he should see message box.
My following code is working up to the point, if user is a member of DistList, he get child form but I don't know how to check show him message box if he isn't member.
string UserName = (string)application.ActiveExplorer().Session.CurrentUser.Name;
string PersonalPublicFolder = "Public Folders - " + application.ActiveExplorer().Session.CurrentUser.AddressEntry.GetExchangeUser().PrimarySmtpAddress;
Outlook.MAPIFolder contactsFolder = outlookNameSpace.Folders[PersonalPublicFolder].Folders["Favorites"];
Outlook.DistListItem addressList = contactsFolder.Items["ContactGroup"];
if (addressList.MemberCount != 0)
{
for (int i = 1; i <= addressList.MemberCount; i++)
{
Outlook.Recipient recipient = addressList.GetMember(i);
string contact = recipient.Name;
if (contact == UserName)
{
var assignOwnership = new AssignOwnership();
assignOwnership.Show();
}
}
}
Any help would be appreciated.
Thank you.
Use Application.Session.CurrentUser.AddressEntry.GetExchangeUser().GetMemberOfList() - it will return AddressEntries object that contains all DLs that the user is a member of.
Be prepared to handle nulls and errors.

Automatically map a Contact to an Account

I want to add a field to Accounts which shows the email domain for that account e.g. #BT.com. I then have a spreadsheet which lists all the Accounts and their email domains. What I want to do is when a new Contact is added to Dynamics that it checks the spreadsheet for the same email domain (obviously without the contacts name in the email) and then assigned the Contact to the Account linked to that domain. Any idea how I would do this. Thanks
Probably best chance would be to develop CRM plugin. Register your plugin to be invoked when on after contact is created or updated (so called post-event phase). And in your plugin update the parentaccountid property of the contact entity to point to account of your choice.
Code-wise it goes something like (disclaimer: not tested):
// IPluginExecutionContext context = null;
// IOrganizationService organizationService = null;
var contact = (Entity)context.InputParameters["Target"];
var email = organizationService.Retrieve("contact", contact.Id, new ColumnSet("emailaddress1")).GetAttributeValue<string>("emailaddress1");
string host;
try
{
var address = new MailAddress(email);
host = address.Host;
}
catch
{
return;
}
var query = new QueryExpression("account");
query.TopCount = 1;
// or whatever the name of email domain field on account is
query.Criteria.AddCondition("emailaddress1", ConditionOperator.Contains, "#" + host);
var entities = organizationService.RetrieveMultiple(query).Entities;
if (entities.Count != 0)
{
contact["parentaccountid"] = entities[0].ToEntityReference();
}
organizationService.Update(contact);
I took Ondrej's code and cleaned it up a bit, re-factored for pre-operation. I also updated the logic to only match active account records and moved the query inside the try/catch. I am unfamiliar with the MailAddress object, I personally would just use string mapping logic.
var target = (Entity)context.InputParameters["Target"];
try
{
string host = new MailAddress(target.emailaddress1).Host;
var query = new QueryExpression("account");
query.TopCount = 1;
// or whatever the name of email domain field on account is
query.Criteria.AddCondition("emailaddress1", ConditionOperator.Contains, "#" + host);
query.Criteria.AddCondition("statecode", ConditionOperator.Equals, 0); //Active records only
var entities = organizationService.RetrieveMultiple(query).Entities;
if (entities.Count != 0)
{
target["parentaccountid"] = entities[0].ToEntityReference();
}
}
catch
{
//Log error
}

Converting string to int, array of strings

I am having an issue with converting a string of id to an int when there are multiple strings passed in, the code shows the following:
for(int i = 0; i < Request.Params["service"].Length; i++)
{
int serviceID = int.Parse(Request.Params["service"]);
db.ServiceAssignments.Add(serviceAssignment);
serviceAssignment.locationID = locationID;
serviceAssignment.ServiceID = serviceID;
db.SaveChanges();
}
If you pass in one param, you get: int.Parse(Request.Params["Service"]); = 1, which then works and the database saves. however if you have the following you get:
'1,2' which three. What I want is 1 and then 2, not 1,2.
What is 1 and 2?
When you create anew location you get to select services for that location. The service id, in the case of this problem is 1 and 2. if I select one service then it saves and all is well. When I select two or more it doesnt work.
I though I could do:
Request.Params["Service"][i] because "Service" is an array after all. How ever this causes database problems and a whole other mess.
So what would you suggest I can do to make it save id 1 and id 2 when you select them for a location?
MVC 3 is quite powerful to figure out the binding, I don't know exactly what are you doing in the view that get the service Ids from user but I assume there is form there and if all Ids are int you can do like this and you don't need any conversion, or maybe you can use FormCollection. I don't think using Request in MVC 3 is a good idea, it does not really belong the whole MVC idea.
public void Add(int[] service)
{
foreach (var item in service)
{
int serviceID = item;
}
}
OR
public void Add(FormCollection frm)
{
foreach (var item in frm.AllKeys)
{
if (item.StartsWith("service"))
{
int serviceID = Int32.Parse(frm[item]);
}
}
}
anyway none of these are also MVC, these are should work but I recommend you to use Models in views and controllers
This will work. Just tested it:
string[] items = Request.Params["service"].Split(',');
for (int i = 0; i < items.Length; i++)
{
int serviceID = int.Parse(items[i]);
db.ServiceAssignments.Add(serviceAssignment);
serviceAssignment.locationID = locationID;
serviceAssignment.ServiceID = serviceID;
db.SaveChanges();
}
As a side note, I'd probably make two changes:
I'd use a foreach statement. No real difference; just less typing.
I'd put the SaveChanges() AFTER the for loop. This will make fewer calls to the database, but still accomplish the same thing.

Resources