Skip to content
Merged
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
19 changes: 6 additions & 13 deletions includes/classes/class-cron.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ private function featured_listing_followup() {
}

if ( directorist_is_monetization_enabled() && directorist_is_featured_listing_enabled() ) {
$featured_days = (int) get_directorist_option( 'featured_listing_time', 30 );
$orders = directorist_order_repository();
$current_time = directorist_now()->getTimestamp();
$orders = directorist_order_repository();
// Define the query
$args = [
'post_type' => ATBDP_POST_TYPE,
Expand All @@ -126,20 +124,15 @@ private function featured_listing_followup() {
// Start the Loop
if ( $listings->found_posts ) {
foreach ( $listings->posts as $listing ) {
$order = $orders->get_latest_paid_featured_order_by_listing_id( $listing->ID );
$has_paid_order = $orders->listing_has_paid_featured_order( $listing->ID );
$has_active_entitlement = $orders->listing_has_active_featured_entitlement( $listing->ID );

if ( ! $order ) {
if ( ! $has_paid_order || $has_active_entitlement ) {
continue;
}

$expiration = ! empty( $order->expires_at )
? new \Directorist\Helpers\DateTime( $order->expires_at )
: ( new \Directorist\Helpers\DateTime( $order->created_at ) )->add_days( $featured_days );

if ( $expiration->getTimestamp() <= $current_time ) {
do_action( 'atbdp_listing_featured_to_general', $listing->ID );
update_post_meta( $listing->ID, '_featured', '' );
}
do_action( 'atbdp_listing_featured_to_general', $listing->ID );
update_post_meta( $listing->ID, '_featured', '' );
}
}
}
Expand Down
44 changes: 32 additions & 12 deletions includes/classes/class-featured-listing-checkout.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function register_hooks() {
}

add_filter( 'directorist_checkout_types', [$this, 'add_checkout_type'] );
add_action( 'directorist_after_order_update', [$this, 'handle_after_order_update'] );
add_action( 'directorist_after_order_update', [$this, 'handle_after_order_update'], 10, 2 );
add_filter( 'directorist_checkout_validation', [$this, 'validate_checkout'], 10, 2 );
add_action( 'directorist_checkout_table', [$this, 'handle_checkout_table'], 10, 4 );
add_filter( 'directorist_checkout_subtotal', [$this, 'handle_checkout_subtotal'], 10, 3 );
Expand Down Expand Up @@ -133,7 +133,7 @@ public function handle_checkout_create_order( OrderDTO $dto, string $checkout_ty
$dto->set_listing_id( $request->get_param( 'listing_id' ) )->set_is_featured_listing( 1 )->set_ref_type( self::CHECKOUT_TYPE )->set_amount( $amount )->set_sub_total( $amount );
}

public function handle_after_order_update( OrderDTO $dto ) {
public function handle_after_order_update( OrderDTO $dto, $old_order = null ) {
if ( ! $this->is_featured_order( $dto ) ) {
return;
}
Expand All @@ -143,31 +143,54 @@ public function handle_after_order_update( OrderDTO $dto ) {
}

if ( Status::PAID === $dto->get_status() ) {
$order_expiration = $this->should_refresh_order_expiration( $dto, $old_order )
? $this->refresh_order_expiration( $dto )
: null;

directorist_set_listing_featured( $dto->get_listing_id(), true );

// Publish the listing if it's pending
$listing = get_post( $dto->get_listing_id() );

if ( $listing ) {
$this->updated_listing_expiration( $listing, $dto );
if ( $listing && $order_expiration ) {
$this->update_listing_expiration( $listing, $order_expiration );
}

if ( $listing && 'publish' !== $listing->post_status ) {
directorist_set_listing_status( $dto->get_listing_id(), 'publish' );
}
} else {
} elseif ( ! directorist_order_repository()->listing_has_active_featured_entitlement( $dto->get_listing_id() ) ) {
directorist_set_listing_featured( $dto->get_listing_id(), false );
}
}

private function updated_listing_expiration( $listing, OrderDTO $order ) {
if ( get_post_meta( $listing->ID, '_never_expire', true ) ) {
return;
}
private function is_paid_transition( $old_order ): bool {
return ! $old_order || ! isset( $old_order->status ) || Status::PAID !== $old_order->status;
}

private function should_refresh_order_expiration( OrderDTO $order, $old_order ): bool {
return $this->is_paid_transition( $old_order ) || ! $order->is_initialized( 'expires_at' );
}

private function refresh_order_expiration( OrderDTO $order ) {
$featured_days = (int) get_directorist_option( 'featured_listing_time', 30 );
$order_expiration = directorist_now()->add_days( $featured_days );

$order->set_expires_at( $order_expiration );
$expiration_update = ( new OrderDTO() )
->set_id( $order->get_id() )
->set_expires_at( $order_expiration );

directorist_order_repository()->silent_update( $expiration_update );

return $order_expiration;
}

private function update_listing_expiration( $listing, $order_expiration ) {
if ( get_post_meta( $listing->ID, '_never_expire', true ) ) {
return;
}

$listing_expiration = get_post_meta( $listing->ID, '_expiry_date', true );
$listing_expiration_date = $listing_expiration
? date_create_from_format( 'Y-m-d H:i:s', $listing_expiration, wp_timezone() )
Expand All @@ -180,9 +203,6 @@ private function updated_listing_expiration( $listing, OrderDTO $order ) {
return;
}

$order->set_expires_at( $order_expiration );
directorist_order_repository()->silent_update( $order );

update_post_meta( $listing->ID, '_expiry_date', $order_expiration->format( 'Y-m-d H:i:s' ) );
}

Expand Down
29 changes: 29 additions & 0 deletions includes/repositories/order-repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,35 @@ public function listing_has_paid_featured_order( int $listing_id ): bool {
return $order ? true : false;
}

public function listing_has_active_featured_entitlement( int $listing_id ): bool {
$orders = $this->get_query_builder()
->select( 'd_order.ref_type', 'd_order.created_at', 'd_order.expires_at' )
->where( 'd_order.listing_id', $listing_id )
->where( 'd_order.is_featured_listing', 1 )
->where( 'd_order.status', OrderStatus::PAID )
->get();

$current_time = directorist_now()->getTimestamp();
$featured_days = (int) get_directorist_option( 'featured_listing_time', 30 );
$is_active = false;

foreach ( $orders as $order ) {
if ( ! empty( $order->expires_at ) ) {
$is_active = ( new DateTime( $order->expires_at ) )->getTimestamp() > $current_time;
} elseif ( 'featured_listing' === $order->ref_type ) {
$is_active = ( new DateTime( $order->created_at ) )->add_days( $featured_days )->getTimestamp() > $current_time;
} else {
$is_active = true;
}

if ( $is_active ) {
break;
}
}

return (bool) apply_filters( 'directorist_listing_has_active_featured_entitlement', $is_active, $listing_id, $orders );
}

public function get_latest_paid_featured_order_by_listing_id( int $listing_id ) {
return $this->get_query_builder()
->select( 'd_order.created_at', 'd_order.expires_at' )
Expand Down
26 changes: 23 additions & 3 deletions includes/repositories/payment-repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Directorist\Utils\Database\Query\Builder;
use Directorist\DTO\Payment\DTO;
use Directorist\Enums\Order\Status as OrderStatus;
use Directorist\Enums\Payment\Status as PaymentStatus;
use Directorist\DBModels\Payment;

class PaymentRepository extends Repository {
Expand All @@ -33,15 +34,34 @@ public function get( $order_id ) {
* @return int
*/
public function create( \Directorist\Utils\DTO $dto ) {
$payment_id = parent::create( $dto );
$payment_id = $this->create_without_order_update( $dto );
$payment = $payment_id ? $this->get_by_id( $payment_id ) : null;

if ( ! $payment || (int) $payment->id !== $payment_id || $payment->status !== $dto->get_status() ) {
return 0;
}

if ( $dto->is_initialized( 'status' ) && $dto->get_status() === OrderStatus::PAID ) {
if ( $dto->is_initialized( 'status' ) && $dto->get_status() === PaymentStatus::PAID ) {
$this->order_repository->update_status( $dto->get_order_id(), OrderStatus::PAID );
}

return $payment_id;
}

/**
* Create a payment without synchronizing the related order status.
*
* @param \Directorist\Utils\DTO $dto Payment data.
* @return int Payment ID, or zero when the insert fails.
*/
public function create_without_order_update( \Directorist\Utils\DTO $dto ) {
global $wpdb;

$payment_id = parent::create( $dto );

return $wpdb->last_error ? 0 : $payment_id;
}

public function update_status_by_order_id( int $order_id, string $status ): int {
return $this->get_query_builder()
->where( 'order_id', $order_id )
Expand Down Expand Up @@ -69,4 +89,4 @@ public function to_dto( $payment ) {

return $dto;
}
}
}
41 changes: 37 additions & 4 deletions includes/rest-api/Version1/class-orders-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Directorist\DTO\Order\DTO as OrderDTO;
use Directorist\DTO\Payment\DTO as PaymentDTO;
use Directorist\Enums\Order\Status as OrderStatus;
use Directorist\Enums\Payment\Status as PaymentStatus;
use WP_Error;
use WP_REST_Request;
use WP_REST_Server;
Expand Down Expand Up @@ -140,7 +141,8 @@ public function create_item( $request ) {

$dto = apply_filters( 'directorist_rest_legacy_order_create_dto', $dto, $request );

$order_id = directorist_order_repository()->create( $dto );
$order_repository = directorist_order_repository();
$order_id = $order_repository->create( $dto );

if ( ! $order_id ) {
return new WP_Error( 'invalid_order', __( 'Unable to create order.', 'directorist' ), array( 'status' => 400 ) );
Expand All @@ -153,11 +155,25 @@ public function create_item( $request ) {
->set_order_id( $order_id )
->set_amount( $amount )
->set_currency( $currency )
->set_status( $this->legacy_status_to_current_status( $legacy_status ) )
->set_status( $this->legacy_payment_status_to_current_status( $legacy_status ) )
->set_method( $gateway )
->set_transaction_id( $transaction_id ? $transaction_id : null );

directorist_payment_repository()->create( apply_filters( 'directorist_rest_legacy_order_create_payment_dto', $payment_dto, $request, $dto ) );
$payment_dto = apply_filters( 'directorist_rest_legacy_order_create_payment_dto', $payment_dto, $request, $dto );
$payment_repository = directorist_payment_repository();
$payment_id = $payment_repository->create_without_order_update( $payment_dto );
$payment = $payment_id ? $payment_repository->get_by_id( $payment_id ) : null;

if ( ! $payment_id || ! $payment || (int) $payment->id !== $payment_id || $payment->status !== $payment_dto->get_status() ) {
$payment_repository->delete_by( 'order_id', $order_id );
$order_repository->delete_by_id( $order_id );

return new WP_Error( 'rest_payment_create_failed', __( 'Unable to create payment.', 'directorist' ), array( 'status' => 500 ) );
}

if ( OrderStatus::PAID === $dto->get_status() ) {
$order_repository->update_status( $order_id, OrderStatus::PAID );
}
}

do_action( 'atbdp_order_created', $order_id, $listing_id );
Expand Down Expand Up @@ -258,6 +274,9 @@ protected function get_order( int $order_id ) {
protected function prepare_legacy_order_data( $order, WP_REST_Request $request ): array {
$payment = ! empty( $order->payment ) ? $order->payment : null;
$plan_id = $this->get_plan_id( $order );
$status = OrderStatus::PREPAID === ( $order->status ?? '' )
? $order->status
: ( $payment->status ?? $order->status ?? '' );

$data = array(
'id' => (int) $order->id,
Expand All @@ -273,7 +292,7 @@ protected function prepare_legacy_order_data( $order, WP_REST_Request $request )
'remaining_featured_listings' => 0,
'amount' => round( (float) ( $order->amount ?? 0 ), 2 ),
'currency' => (string) ( $order->currency ?? '' ),
'payment_status' => $this->current_status_to_legacy_status( $payment->status ?? $order->status ?? '' ),
'payment_status' => $this->current_status_to_legacy_status( $status ),
'payment_gateway' => (string) ( $payment->method ?? '' ),
'transaction_id' => (string) ( $payment->transaction_id ?? '' ),
'created_by' => 'web',
Expand Down Expand Up @@ -315,6 +334,20 @@ protected function legacy_status_to_current_status( string $status ): string {
return $map[ $status ] ?? OrderStatus::PENDING;
}

protected function legacy_payment_status_to_current_status( string $status ): string {
$map = array(
'created' => PaymentStatus::PENDING,
'pending' => PaymentStatus::PENDING,
'prepaid' => PaymentStatus::PAID,
'completed' => PaymentStatus::PAID,
'failed' => PaymentStatus::FAILED,
'cancelled' => PaymentStatus::CANCELLED,
'refunded' => PaymentStatus::REFUNDED,
);

return $map[ $status ] ?? PaymentStatus::PENDING;
}

protected function current_status_to_legacy_status( string $status ): string {
$map = array(
OrderStatus::PENDING => 'pending',
Expand Down
Loading