Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
라이앤캐처스 크루공간
허창호
연습용
Commits
969fb9e8
Commit
969fb9e8
authored
Feb 06, 2022
by
madvirus
Browse files
Initial Commit
parents
Changes
187
Hide whitespace changes
Inline
Side-by-side
src/main/java/com/myshop/order/command/domain/CancelPolicy.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
public
interface
CancelPolicy
{
boolean
hasCancellationPermission
(
Order
order
,
Canceller
canceller
);
}
src/main/java/com/myshop/order/command/domain/Canceller.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
public
class
Canceller
{
private
String
memberId
;
public
Canceller
(
String
memberId
)
{
this
.
memberId
=
memberId
;
}
public
String
getMemberId
()
{
return
memberId
;
}
public
static
Canceller
of
(
String
memberId
)
{
return
new
Canceller
(
memberId
);
}
}
src/main/java/com/myshop/order/command/domain/Order.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
com.myshop.common.event.Events
;
import
com.myshop.common.jpa.MoneyConverter
;
import
com.myshop.common.model.Money
;
import
javax.persistence.*
;
import
java.time.LocalDateTime
;
import
java.util.List
;
@Entity
@Table
(
name
=
"purchase_order"
)
@Access
(
AccessType
.
FIELD
)
public
class
Order
{
@EmbeddedId
private
OrderNo
number
;
@Version
private
long
version
;
@Embedded
private
Orderer
orderer
;
@ElementCollection
(
fetch
=
FetchType
.
LAZY
)
@CollectionTable
(
name
=
"order_line"
,
joinColumns
=
@JoinColumn
(
name
=
"order_number"
))
@OrderColumn
(
name
=
"line_idx"
)
private
List
<
OrderLine
>
orderLines
;
@Convert
(
converter
=
MoneyConverter
.
class
)
@Column
(
name
=
"total_amounts"
)
private
Money
totalAmounts
;
@Embedded
private
ShippingInfo
shippingInfo
;
@Column
(
name
=
"state"
)
@Enumerated
(
EnumType
.
STRING
)
private
OrderState
state
;
@Column
(
name
=
"order_date"
)
private
LocalDateTime
orderDate
;
protected
Order
()
{
}
public
Order
(
OrderNo
number
,
Orderer
orderer
,
List
<
OrderLine
>
orderLines
,
ShippingInfo
shippingInfo
,
OrderState
state
)
{
setNumber
(
number
);
setOrderer
(
orderer
);
setOrderLines
(
orderLines
);
setShippingInfo
(
shippingInfo
);
this
.
state
=
state
;
this
.
orderDate
=
LocalDateTime
.
now
();
Events
.
raise
(
new
OrderPlacedEvent
(
number
.
getNumber
(),
orderer
,
orderLines
,
orderDate
));
}
private
void
setNumber
(
OrderNo
number
)
{
if
(
number
==
null
)
throw
new
IllegalArgumentException
(
"no number"
);
this
.
number
=
number
;
}
private
void
setOrderer
(
Orderer
orderer
)
{
if
(
orderer
==
null
)
throw
new
IllegalArgumentException
(
"no orderer"
);
this
.
orderer
=
orderer
;
}
private
void
setOrderLines
(
List
<
OrderLine
>
orderLines
)
{
verifyAtLeastOneOrMoreOrderLines
(
orderLines
);
this
.
orderLines
=
orderLines
;
calculateTotalAmounts
();
}
private
void
verifyAtLeastOneOrMoreOrderLines
(
List
<
OrderLine
>
orderLines
)
{
if
(
orderLines
==
null
||
orderLines
.
isEmpty
())
{
throw
new
IllegalArgumentException
(
"no OrderLine"
);
}
}
private
void
calculateTotalAmounts
()
{
this
.
totalAmounts
=
new
Money
(
orderLines
.
stream
()
.
mapToInt
(
x
->
x
.
getAmounts
().
getValue
()).
sum
());
}
private
void
setShippingInfo
(
ShippingInfo
shippingInfo
)
{
if
(
shippingInfo
==
null
)
throw
new
IllegalArgumentException
(
"no shipping info"
);
this
.
shippingInfo
=
shippingInfo
;
}
public
OrderNo
getNumber
()
{
return
number
;
}
public
long
getVersion
()
{
return
version
;
}
public
Orderer
getOrderer
()
{
return
orderer
;
}
public
Money
getTotalAmounts
()
{
return
totalAmounts
;
}
public
ShippingInfo
getShippingInfo
()
{
return
shippingInfo
;
}
public
OrderState
getState
()
{
return
state
;
}
public
void
changeShippingInfo
(
ShippingInfo
newShippingInfo
)
{
verifyNotYetShipped
();
setShippingInfo
(
newShippingInfo
);
Events
.
raise
(
new
ShippingInfoChangedEvent
(
number
,
newShippingInfo
));
}
public
void
cancel
()
{
verifyNotYetShipped
();
this
.
state
=
OrderState
.
CANCELED
;
Events
.
raise
(
new
OrderCanceledEvent
(
number
.
getNumber
()));
}
private
void
verifyNotYetShipped
()
{
if
(!
isNotYetShipped
())
throw
new
AlreadyShippedException
();
}
public
boolean
isNotYetShipped
()
{
return
state
==
OrderState
.
PAYMENT_WAITING
||
state
==
OrderState
.
PREPARING
;
}
public
List
<
OrderLine
>
getOrderLines
()
{
return
orderLines
;
}
public
boolean
matchVersion
(
long
version
)
{
return
this
.
version
==
version
;
}
public
void
startShipping
()
{
verifyShippableState
();
this
.
state
=
OrderState
.
SHIPPED
;
Events
.
raise
(
new
ShippingStartedEvent
(
number
.
getNumber
()));
}
private
void
verifyShippableState
()
{
verifyNotYetShipped
();
verifyNotCanceled
();
}
private
void
verifyNotCanceled
()
{
if
(
state
==
OrderState
.
CANCELED
)
{
throw
new
OrderAlreadyCanceledException
();
}
}
}
src/main/java/com/myshop/order/command/domain/OrderAlreadyCanceledException.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
public
class
OrderAlreadyCanceledException
extends
RuntimeException
{
}
src/main/java/com/myshop/order/command/domain/OrderCanceledEvent.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
com.myshop.common.event.Event
;
public
class
OrderCanceledEvent
extends
Event
{
private
String
orderNumber
;
public
OrderCanceledEvent
(
String
number
)
{
super
();
this
.
orderNumber
=
number
;
}
public
String
getOrderNumber
()
{
return
orderNumber
;
}
}
src/main/java/com/myshop/order/command/domain/OrderLine.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
com.myshop.catalog.command.domain.product.ProductId
;
import
com.myshop.common.jpa.MoneyConverter
;
import
com.myshop.common.model.Money
;
import
javax.persistence.Column
;
import
javax.persistence.Convert
;
import
javax.persistence.Embeddable
;
import
javax.persistence.Embedded
;
@Embeddable
public
class
OrderLine
{
@Embedded
private
ProductId
productId
;
@Convert
(
converter
=
MoneyConverter
.
class
)
@Column
(
name
=
"price"
)
private
Money
price
;
@Column
(
name
=
"quantity"
)
private
int
quantity
;
@Convert
(
converter
=
MoneyConverter
.
class
)
@Column
(
name
=
"amounts"
)
private
Money
amounts
;
protected
OrderLine
()
{
}
public
OrderLine
(
ProductId
productId
,
Money
price
,
int
quantity
)
{
this
.
productId
=
productId
;
this
.
price
=
price
;
this
.
quantity
=
quantity
;
this
.
amounts
=
calculateAmounts
();
}
private
Money
calculateAmounts
()
{
return
price
.
multiply
(
quantity
);
}
public
ProductId
getProductId
()
{
return
productId
;
}
public
Money
getPrice
()
{
return
price
;
}
public
int
getQuantity
()
{
return
quantity
;
}
public
Money
getAmounts
()
{
return
amounts
;
}
}
src/main/java/com/myshop/order/command/domain/OrderNo.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
javax.persistence.Column
;
import
javax.persistence.Embeddable
;
import
java.io.Serializable
;
import
java.util.Objects
;
@Embeddable
public
class
OrderNo
implements
Serializable
{
@Column
(
name
=
"order_number"
)
private
String
number
;
protected
OrderNo
()
{
}
public
OrderNo
(
String
number
)
{
this
.
number
=
number
;
}
public
String
getNumber
()
{
return
number
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
OrderNo
orderNo
=
(
OrderNo
)
o
;
return
Objects
.
equals
(
number
,
orderNo
.
number
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
number
);
}
public
static
OrderNo
of
(
String
number
)
{
return
new
OrderNo
(
number
);
}
}
src/main/java/com/myshop/order/command/domain/OrderPlacedEvent.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
java.time.LocalDateTime
;
import
java.util.Date
;
import
java.util.List
;
public
class
OrderPlacedEvent
{
private
String
number
;
private
Orderer
orderer
;
private
List
<
OrderLine
>
orderLines
;
private
LocalDateTime
orderDate
;
private
OrderPlacedEvent
()
{
}
public
OrderPlacedEvent
(
String
number
,
Orderer
orderer
,
List
<
OrderLine
>
orderLines
,
LocalDateTime
orderDate
)
{
this
.
number
=
number
;
this
.
orderer
=
orderer
;
this
.
orderLines
=
orderLines
;
this
.
orderDate
=
orderDate
;
}
public
String
getNumber
()
{
return
number
;
}
public
Orderer
getOrderer
()
{
return
orderer
;
}
public
List
<
OrderLine
>
getOrderLines
()
{
return
orderLines
;
}
public
LocalDateTime
getOrderDate
()
{
return
orderDate
;
}
}
src/main/java/com/myshop/order/command/domain/OrderRepository.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
org.springframework.data.repository.Repository
;
import
java.util.Date
;
import
java.util.Optional
;
import
java.util.concurrent.ThreadLocalRandom
;
public
interface
OrderRepository
extends
Repository
<
Order
,
OrderNo
>
{
Optional
<
Order
>
findById
(
OrderNo
id
);
void
save
(
Order
order
);
default
OrderNo
nextOrderNo
()
{
int
randomNo
=
ThreadLocalRandom
.
current
().
nextInt
(
900000
)
+
100000
;
String
number
=
String
.
format
(
"%tY%<tm%<td%<tH-%d"
,
new
Date
(),
randomNo
);
return
new
OrderNo
(
number
);
}
}
src/main/java/com/myshop/order/command/domain/OrderState.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
public
enum
OrderState
{
PAYMENT_WAITING
,
PREPARING
,
SHIPPED
,
DELIVERING
,
DELIVERY_COMPLETED
,
CANCELED
}
src/main/java/com/myshop/order/command/domain/Orderer.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
com.myshop.member.command.domain.MemberId
;
import
javax.persistence.AttributeOverride
;
import
javax.persistence.AttributeOverrides
;
import
javax.persistence.Column
;
import
javax.persistence.Embeddable
;
import
java.util.Objects
;
@Embeddable
public
class
Orderer
{
@AttributeOverrides
(
@AttributeOverride
(
name
=
"id"
,
column
=
@Column
(
name
=
"orderer_id"
))
)
private
MemberId
memberId
;
@Column
(
name
=
"orderer_name"
)
private
String
name
;
protected
Orderer
()
{
}
public
Orderer
(
MemberId
memberId
,
String
name
)
{
this
.
memberId
=
memberId
;
this
.
name
=
name
;
}
public
MemberId
getMemberId
()
{
return
memberId
;
}
public
String
getName
()
{
return
name
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(
this
==
o
)
return
true
;
if
(
o
==
null
||
getClass
()
!=
o
.
getClass
())
return
false
;
Orderer
orderer
=
(
Orderer
)
o
;
return
Objects
.
equals
(
memberId
,
orderer
.
memberId
)
&&
Objects
.
equals
(
name
,
orderer
.
name
);
}
@Override
public
int
hashCode
()
{
return
Objects
.
hash
(
memberId
,
name
);
}
}
src/main/java/com/myshop/order/command/domain/OrdererService.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
com.myshop.member.command.domain.MemberId
;
public
interface
OrdererService
{
Orderer
createOrderer
(
MemberId
ordererMemberId
);
}
src/main/java/com/myshop/order/command/domain/Receiver.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
javax.persistence.Column
;
import
javax.persistence.Embeddable
;
@Embeddable
public
class
Receiver
{
@Column
(
name
=
"receiver_name"
)
private
String
name
;
@Column
(
name
=
"receiver_phone"
)
private
String
phone
;
public
Receiver
()
{
}
public
Receiver
(
String
name
,
String
phone
)
{
this
.
name
=
name
;
this
.
phone
=
phone
;
}
public
String
getName
()
{
return
name
;
}
public
String
getPhone
()
{
return
phone
;
}
}
src/main/java/com/myshop/order/command/domain/ShippingInfo.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
import
com.myshop.common.model.Address
;
import
javax.persistence.*
;
@Embeddable
public
class
ShippingInfo
{
@Embedded
@AttributeOverrides
({
@AttributeOverride
(
name
=
"zipCode"
,
column
=
@Column
(
name
=
"shipping_zip_code"
)),
@AttributeOverride
(
name
=
"address1"
,
column
=
@Column
(
name
=
"shipping_addr1"
)),
@AttributeOverride
(
name
=
"address2"
,
column
=
@Column
(
name
=
"shipping_addr2"
))
})
private
Address
address
;
@Column
(
name
=
"shipping_message"
)
private
String
message
;
@Embedded
private
Receiver
receiver
;
public
ShippingInfo
()
{
}
public
ShippingInfo
(
Address
address
,
String
message
,
Receiver
receiver
)
{
this
.
address
=
address
;
this
.
message
=
message
;
this
.
receiver
=
receiver
;
}
public
Address
getAddress
()
{
return
address
;
}
public
String
getMessage
()
{
return
message
;
}
public
Receiver
getReceiver
()
{
return
receiver
;
}
}
src/main/java/com/myshop/order/command/domain/ShippingInfoChangedEvent.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
public
class
ShippingInfoChangedEvent
{
private
final
OrderNo
number
;
private
final
ShippingInfo
newShippingInfo
;
private
long
timestamp
;
public
ShippingInfoChangedEvent
(
OrderNo
number
,
ShippingInfo
newShippingInfo
)
{
super
();
this
.
number
=
number
;
this
.
newShippingInfo
=
newShippingInfo
;
this
.
timestamp
=
System
.
currentTimeMillis
();
}
public
OrderNo
getNumber
()
{
return
number
;
}
public
ShippingInfo
getNewShippingInfo
()
{
return
newShippingInfo
;
}
public
long
getTimestamp
()
{
return
timestamp
;
}
}
src/main/java/com/myshop/order/command/domain/ShippingStartedEvent.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.command.domain
;
public
class
ShippingStartedEvent
{
private
String
orderNumber
;
public
ShippingStartedEvent
(
String
number
)
{
this
.
orderNumber
=
number
;
}
public
String
getOrderNumber
()
{
return
orderNumber
;
}
}
src/main/java/com/myshop/order/infra/OrderCanceledEventHandler.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.infra
;
import
com.myshop.order.command.application.RefundService
;
import
com.myshop.order.command.domain.OrderCanceledEvent
;
import
org.springframework.context.event.EventListener
;
import
org.springframework.scheduling.annotation.Async
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.event.TransactionPhase
;
import
org.springframework.transaction.event.TransactionalEventListener
;
@Service
public
class
OrderCanceledEventHandler
{
private
RefundService
refundService
;
public
OrderCanceledEventHandler
(
RefundService
refundService
)
{
this
.
refundService
=
refundService
;
}
@Async
@TransactionalEventListener
(
classes
=
OrderCanceledEvent
.
class
,
phase
=
TransactionPhase
.
AFTER_COMMIT
)
public
void
handle
(
OrderCanceledEvent
event
)
{
refundService
.
refund
(
event
.
getOrderNumber
());
}
}
src/main/java/com/myshop/order/infra/OrdererServiceImpl.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.infra
;
import
com.myshop.member.command.domain.MemberId
;
import
com.myshop.member.query.MemberData
;
import
com.myshop.member.query.MemberQueryService
;
import
com.myshop.order.command.domain.Orderer
;
import
com.myshop.order.command.domain.OrdererService
;
import
org.springframework.stereotype.Service
;
@Service
public
class
OrdererServiceImpl
implements
OrdererService
{
private
MemberQueryService
memberQueryService
;
public
OrdererServiceImpl
(
MemberQueryService
memberQueryService
)
{
this
.
memberQueryService
=
memberQueryService
;
}
@Override
public
Orderer
createOrderer
(
MemberId
ordererMemberId
)
{
MemberData
memberData
=
memberQueryService
.
getMemberData
(
ordererMemberId
.
getId
());
return
new
Orderer
(
MemberId
.
of
(
memberData
.
getId
()),
memberData
.
getName
());
}
}
src/main/java/com/myshop/order/infra/domain/SecurityCancelPolicy.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.infra.domain
;
import
com.myshop.order.command.domain.CancelPolicy
;
import
com.myshop.order.command.domain.Canceller
;
import
com.myshop.order.command.domain.Order
;
import
org.springframework.security.core.Authentication
;
import
org.springframework.security.core.GrantedAuthority
;
import
org.springframework.security.core.context.SecurityContext
;
import
org.springframework.security.core.context.SecurityContextHolder
;
import
org.springframework.stereotype.Component
;
import
java.util.Collection
;
@Component
public
class
SecurityCancelPolicy
implements
CancelPolicy
{
@Override
public
boolean
hasCancellationPermission
(
Order
order
,
Canceller
canceller
)
{
return
isCancellerOrderer
(
order
,
canceller
)
||
isCurrentUserAdminRole
();
}
private
boolean
isCancellerOrderer
(
Order
order
,
Canceller
canceller
)
{
return
order
.
getOrderer
().
getMemberId
().
getId
().
equals
(
canceller
.
getMemberId
());
}
private
boolean
isCurrentUserAdminRole
()
{
SecurityContext
context
=
SecurityContextHolder
.
getContext
();
if
(
context
==
null
)
return
false
;
Authentication
authentication
=
context
.
getAuthentication
();
if
(
authentication
==
null
)
return
false
;
Collection
<?
extends
GrantedAuthority
>
authorities
=
authentication
.
getAuthorities
();
if
(
authorities
==
null
)
return
false
;
return
authorities
.
stream
().
anyMatch
(
authority
->
authority
.
getAuthority
().
equals
(
"ROLE_ADMIN"
));
}
}
src/main/java/com/myshop/order/infra/paygate/ExternalRefundService.java
0 → 100644
View file @
969fb9e8
package
com.myshop.order.infra.paygate
;
import
com.myshop.order.command.application.RefundService
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.stereotype.Component
;
@Component
public
class
ExternalRefundService
implements
RefundService
{
private
Logger
logger
=
LoggerFactory
.
getLogger
(
getClass
());
@Override
public
void
refund
(
String
orderNumber
)
{
logger
.
info
(
"refund order[{}]"
,
orderNumber
);
}
}
Prev
1
2
3
4
5
6
7
8
9
10
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment