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

feature/credit-purchase #141

Merged
merged 3 commits into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions sep490-enterprise/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.kafka:spring-kafka'
implementation 'vn.payos:payos-java:1.0.3'

// Testing
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package green_buildings.idp.configs;
package enterprise.configs;

import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package enterprise.dtos;

import java.util.UUID;

public record CreditPackageDTO(UUID id, int version, int numberOfCredits, long price) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package enterprise.dtos;

public record CreditPurchaseDTO(Long code, Integer amount, Integer price) {
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package enterprise.entities;

import commons.springfw.impl.entities.AbstractAuditableEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Table(name = "credit_packages")
@Getter
@Setter
@NoArgsConstructor
public class CreditPackageEntity extends AbstractAuditableEntity {

@Column(name = "number_of_credits", nullable = false)
@Min(0)
@NotNull
private int numberOfCredits = 0;

@Column(name = "price", nullable = false)
@Min(0)
@NotNull
private long price = 0;

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ public class PaymentEntity extends AbstractAuditableEntity {
@JoinColumn(name = "enterprise_id", nullable = false)
private EnterpriseEntity enterprise;

@NotNull
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "bundle_id", nullable = false)
private BundleEntity bundle;

@NotNull
@Enumerated(EnumType.STRING)
@Column(name = "status")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package enterprise.mappers;

import enterprise.dtos.CreditPackageDTO;
import enterprise.entities.CreditPackageEntity;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;

@Mapper(componentModel = MappingConstants.ComponentModel.SPRING)
public interface CreditPackageMapper {

CreditPackageDTO entityToDTO(CreditPackageEntity creditPackageEntity);

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package enterprise.repositories;

import commons.springfw.impl.repositories.AbstractBaseRepository;
import enterprise.entities.CreditPackageEntity;

public interface CreditPackageRepository extends AbstractBaseRepository<CreditPackageEntity> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package enterprise.rest;

import enterprise.dtos.CreditPackageDTO;
import enterprise.mappers.CreditPackageMapper;
import enterprise.services.CreditPackageService;
import green_buildings.commons.api.security.UserRole;
import jakarta.annotation.security.RolesAllowed;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/api/credit-package")
@RequiredArgsConstructor
public class CreditPackageController {

private final CreditPackageService creditPackageService;
private final CreditPackageMapper mapper;

@GetMapping
@RolesAllowed({UserRole.RoleNameConstant.SYSTEM_ADMIN, UserRole.RoleNameConstant.ENTERPRISE_OWNER})
public List<CreditPackageDTO> findAll() {
return creditPackageService.findAll()
.stream()
.map(mapper::entityToDTO)
.toList();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package enterprise.services;

import enterprise.entities.CreditPackageEntity;

import java.util.List;

public interface CreditPackageService {
List<CreditPackageEntity> findAll();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package enterprise.services;

import enterprise.entities.CreditPackageEntity;
import enterprise.repositories.CreditPackageRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional(rollbackOn = Throwable.class)
public class CreditPackageServiceImpl implements CreditPackageService {

private final CreditPackageRepository creditPackageRepository;

@Override
public List<CreditPackageEntity> findAll() {
return creditPackageRepository.findAll();
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
package enterprise.services.impl;

import commons.springfw.impl.utils.SecurityUtils;
import enterprise.dtos.CreditPurchaseDTO;
import enterprise.dtos.PaymentCriteriaDTO;
import enterprise.entities.PaymentEntity;
import enterprise.repositories.PaymentRepository;
import enterprise.services.PaymentService;
import green_buildings.commons.api.dto.SearchCriteriaDTO;
import green_buildings.commons.api.exceptions.TechnicalException;
import jakarta.annotation.PostConstruct;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import vn.payos.PayOS;
import vn.payos.type.CheckoutResponseData;
import vn.payos.type.ItemData;
import vn.payos.type.PaymentData;

import java.util.UUID;

Expand All @@ -21,10 +30,66 @@
@RequiredArgsConstructor
public class PaymentServiceImpl implements PaymentService {
private final PaymentRepository payRepo;
private final PayOS payOS;

@Value("${payment.payos.returnPath}")
private String returnPath;

@Value("${payment.payos.cancelPath}")
private String cancelPath;

@Value("${spring.application.homepage}")
private String homepage;

private String returnUrl;
private String cancelUrl;

@PostConstruct
public void setUrls() {
returnUrl = UriComponentsBuilder.fromUriString(homepage)
.path(returnPath)
.build()
.toUriString();
cancelUrl = UriComponentsBuilder.fromUriString(homepage)
.path(cancelPath)
.build()
.toUriString();
}

@Override
public Page<PaymentEntity> search(SearchCriteriaDTO<PaymentCriteriaDTO> searchCriteria, Pageable pageable) {
UUID enterpriseId = SecurityUtils.getCurrentUserEnterpriseId().orElseThrow();
return payRepo.findByEnterpriseId(enterpriseId, pageable);
}

public CheckoutResponseData getCheckoutData(CreditPurchaseDTO creditPurchaseItem) {
try {
log.info("Creating payment link for item: {}", creditPurchaseItem);
PaymentData paymentData = createPaymentData(creditPurchaseItem);
log.debug("Generated PaymentData: {}", paymentData);
return payOS.createPaymentLink(paymentData);
} catch (Exception ex) {
log.error("Error creating payment link for item: {}", creditPurchaseItem);
throw new TechnicalException("Error creating payment link for item", ex);
}
}

private PaymentData createPaymentData(CreditPurchaseDTO creditPurchaseItem) {
ItemData itemData = createItemData(creditPurchaseItem);
return PaymentData.builder()
.orderCode(creditPurchaseItem.code())
.amount(creditPurchaseItem.price())
.item(itemData)
.returnUrl(returnUrl)
.cancelUrl(cancelUrl)
.build();
}

private ItemData createItemData(CreditPurchaseDTO creditPurchaseItem) {
return ItemData.builder()
.name("Credit Purchase")
.quantity(creditPurchaseItem.amount())
.price(creditPurchaseItem.price())
.build();
}
}
11 changes: 10 additions & 1 deletion sep490-enterprise/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ spring:
issuer-uri: ${ISSUER_URI}
application:
name: enterprise
homepage: http://localhost:4200
datasource:
url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}?serverTimezone=UTC
username: ${POSTGRES_USER}
Expand Down Expand Up @@ -57,4 +58,12 @@ logging:
SQL: ${HIBERNATE_SQL_LOG_LEVEL:TRACE}
type:
descriptor:
sql: ${HIBERNATE_SQL_PARAM_LOG_LEVEL:TRACE}
sql: ${HIBERNATE_SQL_PARAM_LOG_LEVEL:TRACE}

payment:
payos:
client_id: ${PAYOS_CLIENT_ID:not_a_real_key_to_prevent_null}
api_key: ${PAYOS_API_KEY:not_a_real_key_to_prevent_null}
checksum_key: ${PAYOS_CHECKSUM_KEY:not_a_real_key_to_prevent_null}
returnPath: /success-payment
cancelPath: /fail-payment
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ALTER TABLE payments DROP CONSTRAINT payments_fk_bundles;
ALTER TABLE payments DROP COLUMN bundle_id;
ALTER TABLE bundles RENAME TO credit_packages;

ALTER TABLE credit_packages
ADD COLUMN number_of_credits INT NOT NULL DEFAULT 0,
ADD COLUMN price BIGINT NOT NULL DEFAULT 0;
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {UUID} from '../../../../../types/uuid';
import {AppRoutingConstants} from '../../../../app-routing.constant';
import {BuildingService} from '../../../../services/building.service';
import {AbstractFormComponent} from '../../../shared/components/form/abstract-form-component';
import {BuildingDetails} from '../../models/building-details.dto';
import {BuildingDetails} from '../../models/enterprise.dto';

@Component({
selector: 'app-building-detail',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {UUID} from '../../../../../types/uuid';
import {AppRoutingConstants} from '../../../../app-routing.constant';
import {BuildingService} from '../../../../services/building.service';
import {SubscriptionAwareComponent} from '../../../core/subscription-aware.component';
import {Building} from '../../models/building.dto';
import {Building} from '../../models/enterprise.dto';
import {MarkerService} from '../../services/marker.service';
import {RegionService} from '../../services/region.service';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<div class="flex gap-2.5 flex-col">
<div class="flex items-center justify-between lg:flex-row gap-2.5">
<p-button
(onClick)="navigateToSubscription()"
severity="primary"
[label]="'payment.history.button.buyCredit' | translate"
outlined
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {Component, OnInit, TemplateRef, ViewChild} from '@angular/core';
import {Router} from '@angular/router';
import {AppRoutingConstants} from '../../../../app-routing.constant';
import {SubscriptionAwareComponent} from '../../../core/subscription-aware.component';
import {TableTemplateColumn} from '../../../shared/components/table-template/table-template.component';
import {
Expand Down Expand Up @@ -43,7 +45,8 @@ export class PaymentComponent
constructor(
protected readonly applicationService: ApplicationService,
private readonly paymentService: PaymentService,
private readonly walletService: WalletService
private readonly walletService: WalletService,
private readonly router: Router
) {
super();
}
Expand Down Expand Up @@ -96,4 +99,12 @@ export class PaymentComponent
})
);
}

navigateToSubscription(): void {
void this.router.navigate([
'/',
AppRoutingConstants.ENTERPRISE_PATH,
AppRoutingConstants.PLAN_PATH
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
</div>
<!-- Body: Credit Value -->
<div body class="text-lg font-semibold">
{{ package.credits }}
{{ package.numberOfCredits }}
{{ "payment.history.credit.title" | translate }}
</div>

Expand All @@ -105,7 +105,7 @@
footer
class="text-gray-600 text-base font-medium text-center"
>
{{ package.price }}
{{ package.price | number: "1.0-0" }} VND
</div>
</card-template>
}
Expand Down
Loading