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

Added custom amounts for generating oneoff links #114

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ EESTIINTERNETISA.p12

docker-compose.yml

vendor/gems
Dockerfile.dev

# vendor/gems
/public/assets
/public/packs
/public/packs-test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ class OneoffController < Api::V1::InvoiceGenerator::BaseController
The link where the user must be redirected after payment. Along with the transition also on this link comes the data about the payment. This is a kind of redirect_url and callback_url
HERE
param :reference_number, String, required: false
param :amount, String, required: false

def create
response = Oneoff.call(invoice_number: params[:invoice_number],
customer_url: params[:customer_url],
reference_number: params[:reference_number])
reference_number: params[:reference_number],
amount: params[:amount])
if response.result?
render json: { 'message' => 'Link created',
'oneoff_redirect_link' => response.instance['payment_link'] },
Expand Down
22 changes: 21 additions & 1 deletion app/models/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Invoice < ApplicationRecord
}

enum affiliation: { regular: 0, auction_deposit: 1, linkpay: 2 }
enum status: { unpaid: 0, paid: 1, cancelled: 2, failed: 3, refunded: 4, overdue: 5 }
enum status: { unpaid: 0, paid: 1, cancelled: 2, failed: 3, refunded: 4, overdue: 5, partially_paid: 6 }

scope :with_status, lambda { |status|
where(status:) if status.present?
Expand All @@ -29,6 +29,10 @@ class Invoice < ApplicationRecord
where(transaction_amount: low.to_f..high.to_f) if low.present? && high.present?
}

validate :payment_reference_must_change, if: :payment_reference_present_in_params?

attr_accessor :payment_reference_in_params

def self.search(params = {})
sort_column = params[:sort].presence_in(%w[invoice_number status affiliation]) || 'id'
sort_direction = params[:direction].presence_in(%w[asc desc]) || 'desc'
Expand Down Expand Up @@ -61,6 +65,10 @@ def billing_system?
initiator == BILLING_SYSTEM
end

def fully_paid?(amount)
amount.to_f >= transaction_amount.to_f
end

def to_h
{
invoice_number:,
Expand All @@ -74,4 +82,16 @@ def to_h
sent_at_omniva:
}
end

private

def payment_reference_present_in_params?
payment_reference_in_params
end

def payment_reference_must_change
if payment_reference.present? && payment_reference == payment_reference_was
errors.add(:payment_reference, 'must be different from the existing payment reference')
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think better will be

def payment_reference_must_change
    return unless payment_reference.present? && payment_reference == payment_reference_was

    errors.add(:payment_reference, 'must be different from the existing payment reference')
end

end
end
23 changes: 16 additions & 7 deletions app/services/notify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def self.call(response:)
end
return if invoice.paid?

notifier.update_invoice_state(parsed_response:, invoice:)
return unless invoice.paid?
return unless notifier.update_invoice_state(parsed_response:, invoice:)
return if !invoice.paid? && !invoice.partially_paid?
return if invoice.billing_system?

url = notifier.get_update_payment_url[invoice.initiator.to_sym]
Expand Down Expand Up @@ -68,12 +68,21 @@ def notify(title:, error_message:)
end

def update_invoice_state(parsed_response:, invoice:)
status = parsed_response[:payment_state] == SETTLED ? :paid : :failed
paid_status = invoice.fully_paid?(parsed_response[:initial_amount]) ? :paid : :partially_paid
status = parsed_response[:payment_state] == SETTLED ? paid_status : :failed

invoice.update(payment_reference: parsed_response[:payment_reference],
status:,
transaction_time: parsed_response[:transaction_time],
everypay_response: parsed_response)
invoice.payment_reference_in_params = parsed_response.key?(:payment_reference)
invoice.assign_attributes(
payment_reference: parsed_response[:payment_reference],
status:,
transaction_time: parsed_response[:transaction_time],
everypay_response: parsed_response
)

return true if invoice.save

Rails.logger.info("Error saving invoice #{invoice.invoice_number}: #{invoice.errors.full_messages.to_sentence}")
false
end

def invoice_numbers_from_multi_payment(invoice)
Expand Down
15 changes: 9 additions & 6 deletions app/services/oneoff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@ class Oneoff
include Request
include ApplicationService

attr_reader :invoice_number, :customer_url, :reference_number, :bulk, :bulk_invoices
attr_reader :invoice_number, :customer_url, :reference_number, :amount, :bulk, :bulk_invoices

def initialize(invoice_number:, customer_url:, reference_number:, bulk: false, bulk_invoices: [])
def initialize(invoice_number:, customer_url:, reference_number:, amount: nil, bulk: false, bulk_invoices: [])
@invoice = Invoice.find_by(invoice_number: invoice_number)

@invoice_number = invoice_number
@customer_url = customer_url
@reference_number = reference_number
@amount = amount
@bulk = bulk
@bulk_invoices = bulk_invoices
end

def self.call(invoice_number:, customer_url:, reference_number:, bulk: false, bulk_invoices: [])
def self.call(invoice_number:, customer_url:, reference_number:, amount: nil, bulk: false, bulk_invoices: [])
new(invoice_number: invoice_number,
customer_url: customer_url,
reference_number: reference_number,
amount: amount,
bulk: bulk,
bulk_invoices: bulk_invoices).call
end
Expand Down Expand Up @@ -52,6 +54,7 @@ def call

def base_request
uri = URI("#{GlobalVariable::BASE_ENDPOINT}#{GlobalVariable::ONEOFF_ENDPOINT}")

post(direction: 'everypay', path: uri, params: body)
end

Expand All @@ -61,12 +64,12 @@ def body
{
'api_username' => GlobalVariable::API_USERNAME,
'account_name' => GlobalVariable::ACCOUNT_NAME,
'amount' => @invoice.transaction_amount.to_f,
'amount' => amount ? amount.to_f : @invoice.transaction_amount.to_f,
'order_reference' => bulk ? bulk_description.to_s : @invoice.invoice_number.to_s,
# 'token_agreement' => 'unscheduled',
'request_token' => false,
'nonce' => "#{rand(10 ** 30).to_s.rjust(30,'0')}",
'timestamp' => "#{Time.zone.now.to_formatted_s(:iso8601)}",
'nonce' => rand(10**30).to_s.rjust(30, '0'),
'timestamp' => Time.zone.now.to_formatted_s(:iso8601),
'customer_url' => customer_url,
'preferred_country' => 'EE',
'locale' => 'en',
Expand Down
2 changes: 1 addition & 1 deletion spec/requests/api/v1/invoice_generator/oneoff_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
.to_return(status: 200, body: payment_link.to_json, headers: {})
end

it 'should return the payment link if intiiator is eeid' do
it 'should return the payment link if initiator is eeid' do
payload = {
invoice_number: invoice.invoice_number,
customer_url: customer_url_eeid,
Expand Down
30 changes: 27 additions & 3 deletions spec/services/notify_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
payment_state: 'settled',
transaction_time: Time.zone.now - 1.hour,
order_reference: invoice.invoice_number.to_s,
payment_reference: 'test'
payment_reference: 'test',
initial_amount: invoice.transaction_amount
}

Notify.call(response: JSON.parse(everypay_response.to_json))
Expand All @@ -41,6 +42,27 @@
expect(invoice.status).to eq('paid')
end

it 'should mark single invoice as partially_paid if settled and not fully paid' do
invoice.initiator = 'auction'
invoice.invoice_number = 3
invoice.save
expect(invoice.initiator).to eq('auction')
expect(invoice.status).to eq('unpaid')

everypay_response = {
payment_state: 'settled',
transaction_time: Time.zone.now - 1.hour,
order_reference: invoice.invoice_number.to_s,
payment_reference: 'test',
initial_amount: invoice.transaction_amount.to_f - 1
}

Notify.call(response: JSON.parse(everypay_response.to_json))
invoice.reload

expect(invoice.status).to eq('partially_paid')
end

it 'should mark multiple invoices as paid' do
invoice_one.save
invoice_two.save
Expand All @@ -63,7 +85,8 @@
payment_state: 'settled',
transaction_time: Time.zone.now - 1.hour,
order_reference: "ref:#{invoice_three.invoice_number}, #{invoice_three.description.split(' ').join(', ')}",
payment_reference: 'test'
payment_reference: 'test',
initial_amount: invoice_three.transaction_amount
}

Notify.call(response: JSON.parse(everypay_response.to_json))
Expand Down Expand Up @@ -116,7 +139,8 @@
payment_state: 'settled',
transaction_time: Time.zone.now - 1.hour,
order_reference: invoice.invoice_number.to_s,
payment_reference: 'test'
payment_reference: 'test',
initial_amount: invoice.transaction_amount
}

response = Notify.call(response: JSON.parse(everypay_response.to_json))
Expand Down
23 changes: 21 additions & 2 deletions spec/services/oneoff_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
RSpec.describe Oneoff do
payment_link = { 'payment_link' => 'https://everypay.ee' }

describe 'successful case' do
let(:invoice) { create(:invoice) }
let(:customer_url_registry) { GlobalVariable::BASE_REGISTRY }
Expand All @@ -7,8 +9,6 @@
let(:customer_url_auction) { GlobalVariable::BASE_AUCTION }
let(:reference) { create(:reference) }

payment_link = { 'payment_link' => 'https://everypay.ee' }

before(:each) do
stub_request(:post, "#{GlobalVariable::BASE_ENDPOINT}#{GlobalVariable::ONEOFF_ENDPOINT}")
.to_return(status: 200, body: payment_link.to_json, headers: {})
Expand Down Expand Up @@ -50,6 +50,25 @@
end
end

describe 'with custom amount' do
let(:invoice) { create(:invoice) }
let(:customer_url_auction) { GlobalVariable::BASE_AUCTION }

before do
stub_request(:post, "#{GlobalVariable::BASE_ENDPOINT}#{GlobalVariable::ONEOFF_ENDPOINT}")
.with(body: /"amount":100.0/)
.to_return(status: 200, body: payment_link.to_json, headers: {})
end

it 'should generate oneoff link for auction' do
response = described_class.call(invoice_number: invoice.invoice_number.to_s,
customer_url: customer_url_auction,
reference_number: nil,
amount: 100)
expect(response.instance).to a_hash_including(payment_link)
end
end

describe 'invalid case' do
let(:invoice) { create(:invoice) }

Expand Down
Loading