Add full project files
This commit is contained in:
1185
controllers/application/payment/paymentController.js
Normal file
1185
controllers/application/payment/paymentController.js
Normal file
File diff suppressed because it is too large
Load Diff
935
controllers/application/payment/paymentControllerWeb.js
Normal file
935
controllers/application/payment/paymentControllerWeb.js
Normal file
@@ -0,0 +1,935 @@
|
||||
/* eslint-disable eqeqeq */
|
||||
|
||||
const TypeAndPriceModel = require('../../../models/TypeAndPriceModel');
|
||||
const ProjectModel = require('../../../models/ProjectModel');
|
||||
const PaymentModel = require('../../../models/PaymentModel');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const RequestModel = require('../../../models/RequestModel');
|
||||
const NotificationModel = require('../../../models/NotificationModel');
|
||||
const UserModel = require('../../../models/UserModel');
|
||||
const AdvertisingTypeModel = require('../../../models/AdvertisingTypeModel');
|
||||
const AdvertisingModel = require('../../../models/AdvertisingModel');
|
||||
const OfferTypeModel = require('../../../models/OfferTypeModel');
|
||||
const OfferModel = require('../../../models/OfferModel');
|
||||
const { default: axios } = require('axios');
|
||||
|
||||
const apiKey = "c7c41e8a-918f-4741-bcd5-58f3bc51db73"; // اصلاح نام متغیر محیطی
|
||||
|
||||
// Function to get price based on item name from database
|
||||
const getPriceFromDatabase = async (itemName) => {
|
||||
const item = await TypeAndPriceModel.findOne({ name: itemName });
|
||||
if (!item) {
|
||||
throw new Error(`Item "${itemName}" not found in TypeAndPriceModel`);
|
||||
}
|
||||
return item.price;
|
||||
};
|
||||
|
||||
const getAdvertisingPriceFromDatabase = async (itemName) => {
|
||||
const item = await AdvertisingTypeModel.findOne({ name: itemName });
|
||||
if (!item) {
|
||||
throw new Error(`Item "${itemName}" not found in AdvertisingTypeModel`);
|
||||
}
|
||||
return item.price;
|
||||
};
|
||||
|
||||
const getOfferPriceFromDatabase = async (offerType) => {
|
||||
const item = await OfferTypeModel.findOne({ name: offerType });
|
||||
if (!item) {
|
||||
throw new Error(`Offer type "${offerType}" not found in OfferTypeModel`);
|
||||
}
|
||||
return item.price;
|
||||
};
|
||||
// Controller function for initiating payment
|
||||
const initiatePaymentWeb = async (req, res) => {
|
||||
try {
|
||||
const token = req.header('Authorization').split(' ')[1]
|
||||
if (!token) return res.status(401).send('Access Denied')
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const decodedToken = jwt.verify(token, process.env.APP_SECRET)
|
||||
const userId = decodedToken.id
|
||||
const itemName = req.body.item_name // Get item name from request body
|
||||
const price = await getPriceFromDatabase(itemName) // Get price from database
|
||||
const projectId = req.body.projectId // Get project ID from request body
|
||||
// Save project ID for later use in callback URL
|
||||
req.session.projectId = projectId
|
||||
const item = await TypeAndPriceModel.findOne({ name: itemName })
|
||||
const user = await UserModel.findById(userId)
|
||||
|
||||
if (item.name === 'free' && item.price === 0) {
|
||||
if (user.daily_free_request > 0) {
|
||||
user.daily_free_request -= 1
|
||||
await user.save()
|
||||
const project = await ProjectModel.findById(projectId)
|
||||
if (!project) {
|
||||
res.status(404).send('Project not found')
|
||||
return
|
||||
}
|
||||
project.payment_status = 'done' // Set project status to 'done'
|
||||
project.status = 'paid' // Set project status to 'done'
|
||||
await project.save()
|
||||
res.status(200).json({ message: 'پروژه رایگان با موفقیت ایجاد شد', projectId, type: 'free' })
|
||||
} else {
|
||||
res.status(403).json({ message: 'شما قبلاً از درخواست رایگان امروز استفاده کردهاید.' })
|
||||
}
|
||||
} else {
|
||||
const response = await axios.post('https://www.zarinpal.com/pg/rest/WebGate/PaymentRequest.json', {
|
||||
MerchantID: apiKey,
|
||||
Amount: Number(price),
|
||||
Description: `پرداخت برای سفارش شماره ${projectId}`,
|
||||
CallbackURL: `${process.env.APP_URL}/projects/payment-web?projectId=${projectId}&itemName=${itemName}&userId=${userId}` // Assuming your backend URL for handling payment callback
|
||||
})
|
||||
|
||||
const data = response.data
|
||||
if (data.Status === 100) {
|
||||
// Payment request was successful
|
||||
const authority = data.Authority // The payment authority (شناسه پرداخت)
|
||||
res.status(200).json({ authority })
|
||||
} else {
|
||||
// Payment request failed
|
||||
console.error('Error occurred while initiating payment:', data)
|
||||
res.status(500).json({ error: 'Error occurred while initiating payment' })
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Error occurred while getting price from database or sending the request
|
||||
console.error('Error occurred:', error)
|
||||
res.status(500).json({ error: 'Internal server error' })
|
||||
}
|
||||
}
|
||||
// Controller function for handling payment callback from ZarinPal
|
||||
const handlePaymentCallbackWeb = async (req, res) => {
|
||||
try {
|
||||
// console.log(req.query)
|
||||
// Extract payment status and authority from ZarinPal callback
|
||||
const status = req.query.Status
|
||||
const authority = req.query.Authority
|
||||
const projectId = req.query.projectId // Get project ID from session
|
||||
const itemName = req.query.itemName // Get project ID from session
|
||||
const userId = req.query.userId // Get project ID from session
|
||||
// Clear project ID from session
|
||||
// Query ZarinPal API to verify payment status
|
||||
const verificationUrl = 'https://www.zarinpal.com/pg/rest/WebGate/PaymentVerification.json'
|
||||
const price = await getPriceFromDatabase(itemName) // Get price from database
|
||||
const verificationResponse = await axios.post(verificationUrl, {
|
||||
MerchantID: apiKey,
|
||||
Authority: authority,
|
||||
Amount: Number(price)
|
||||
})
|
||||
|
||||
const verificationData = verificationResponse.data
|
||||
if (verificationData.Status === 100) {
|
||||
const payment = new PaymentModel({
|
||||
amount: Number(price),
|
||||
status: 'successful',
|
||||
authority,
|
||||
user_id: userId, // فرضاً شما از نوع میانافزارهای مدیریت کاربر استفاده میکنید و اطلاعات کاربر را از طریق `req.user` در دسترس دارید
|
||||
project_id: projectId,
|
||||
type: 'create',
|
||||
installment_step: null
|
||||
// دیگر اطلاعات مورد نیاز برای ثبت پرداخت
|
||||
})
|
||||
await payment.save()
|
||||
|
||||
// Payment verification is successful
|
||||
// Now, update project status to 'done' or desired status
|
||||
const project = await ProjectModel.findById(projectId)
|
||||
if (!project) {
|
||||
res.status(404).send('Project not found')
|
||||
return
|
||||
}
|
||||
project.payment_status = 'done' // Set project status to 'done'
|
||||
project.status = 'paid' // Set project status to 'done'
|
||||
await project.save()
|
||||
|
||||
// Send event based on payment status
|
||||
if ('eventEmitter' in req.app) {
|
||||
if (status === 'OK') {
|
||||
// Payment is successful
|
||||
// Emit an event to be listened to in the frontend
|
||||
// Example event name: 'paymentSuccess'
|
||||
// Example data: { message: 'Payment successful' }
|
||||
// You can customize the event name and data as needed
|
||||
req.app.get('eventEmitter').emit('paymentSuccess', { message: 'Payment successful' })
|
||||
} else {
|
||||
// Payment is canceled or failed
|
||||
// Emit an event to be listened to in the frontend
|
||||
// Example event name: 'paymentFailed'
|
||||
// Example data: { message: 'Payment canceled or failed' }
|
||||
// You can customize the event name and data as needed
|
||||
req.app.get('eventEmitter').emit('paymentFailed', { message: 'Payment canceled or failed' })
|
||||
}
|
||||
} else {
|
||||
console.error('Error: eventEmitter is not defined or not properly configured.')
|
||||
}
|
||||
|
||||
// Redirect to the callback URL with the project ID
|
||||
res.redirect(`https://modstagram.com/projects/payment/success?projectId=${projectId}&price=${price}&type=create`)
|
||||
} else {
|
||||
// Payment verification failed
|
||||
const payment = new PaymentModel({
|
||||
amount: Number(price),
|
||||
status: 'failed',
|
||||
authority,
|
||||
user_id: userId, // فرضاً شما از نوع میانافزارهای مدیریت کاربر استفاده میکنید و اطلاعات کاربر را از طریق `req.user` در دسترس دارید
|
||||
project_id: projectId,
|
||||
type: 'create'
|
||||
// دیگر اطلاعات مورد نیاز برای ثبت پرداخت
|
||||
})
|
||||
await payment.save()
|
||||
res.redirect(`https://modstagram.com/projects/payment/failed?projectId=${projectId}&price=${price}&type=create`)
|
||||
}
|
||||
} catch (error) {
|
||||
// Error occurred while verifying payment
|
||||
console.error('Error occurred:', error)
|
||||
res.status(500).send('Internal server error')
|
||||
}
|
||||
}
|
||||
|
||||
const paymentRequestAcceptWeb = async (req, res) => {
|
||||
try {
|
||||
const token = req.header('Authorization').split(' ')[1]
|
||||
if (!token) return res.status(401).send('Access Denied')
|
||||
const decodedToken = jwt.verify(token, process.env.APP_SECRET)
|
||||
const userId = decodedToken.id
|
||||
const projectId = req.body.projectId
|
||||
// Find the project
|
||||
const project = await ProjectModel.findById(projectId)
|
||||
if (!project) {
|
||||
return res.status(404).json({ error: 'Project not found' })
|
||||
}
|
||||
if (project.status == 'ongoing') {
|
||||
return res.status(400).json({ message: 'برای این پروژه از قبل کاربر انتخاب شده' })
|
||||
}
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (userId != project.creator_id.toString()) {
|
||||
return res.status(422).json({
|
||||
error: true,
|
||||
message: 'شما نمیتوانید این پروژه را ویرایش کنید'
|
||||
})
|
||||
}
|
||||
|
||||
// Get the final price from the request model
|
||||
const requestId = req.body.requestId
|
||||
const request = await RequestModel.findById(requestId)
|
||||
if (!request) {
|
||||
return res.status(404).json({ error: 'Request not found' })
|
||||
}
|
||||
request.status = 'accepted'
|
||||
await request.save()
|
||||
|
||||
project.selected_user = request.user
|
||||
project.status = 'ongoing'
|
||||
project.final_price = request.price
|
||||
project.final_time = request.time
|
||||
await project.save()
|
||||
// Send notification to selected user
|
||||
const notification = new NotificationModel({
|
||||
user_id: request.user,
|
||||
project_post_id: projectId,
|
||||
type: 'request_accepted',
|
||||
title: 'انتخاب پیشنهاد',
|
||||
description: `کارفرما پیشنهاد کاری شما برای پروژه ${project.title} را پذیرفت.`
|
||||
})
|
||||
await notification.save()
|
||||
|
||||
// Sms
|
||||
const userReciver = await UserModel.findById(request.user)
|
||||
const data = JSON.stringify({
|
||||
mobile: userReciver?.mobile,
|
||||
templateId: '302876',
|
||||
parameters: [
|
||||
{ name: 'USER', value: userReciver?.first_name + ' ' + userReciver?.last_name },
|
||||
{ name: 'PROJECT', value: project?.title }
|
||||
]
|
||||
})
|
||||
const config = {
|
||||
method: 'post',
|
||||
url: 'https://api.sms.ir/v1/send/verify',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'text/plain',
|
||||
'x-api-key': '2JKxGbTzE64t0YTkjip6RYHnm9mq1haMlidF8WWwQunwubHFVW6iaMmfFQbMXEDt'
|
||||
},
|
||||
data
|
||||
}
|
||||
axios(config)
|
||||
.then(function (response) {
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log(error)
|
||||
})
|
||||
res.status(200).json({
|
||||
message: 'درخواست با موفقیت تایید شد'
|
||||
})
|
||||
} catch (error) {
|
||||
// Error occurred while getting price from database or sending the request
|
||||
console.error('Error occurred:', error)
|
||||
res.status(500).json({ error: 'Internal server error' })
|
||||
}
|
||||
}
|
||||
const initiateAdvertisingPaymentWeb = async (req, res) => {
|
||||
try {
|
||||
const token = req.header('Authorization').split(' ')[1]
|
||||
if (!token) return res.status(401).send('Access Denied')
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const decodedToken = jwt.verify(token, process.env.APP_SECRET)
|
||||
const userId = decodedToken.id
|
||||
const itemName = req.body.item_name // Get item name from request body
|
||||
const price = await getAdvertisingPriceFromDatabase(itemName) // Get price from database
|
||||
const advertisingId = req.body.advertisingId // Get project ID from request body
|
||||
const showDiscount = req.body.showDiscount
|
||||
|
||||
// Save project ID for later use in callback URL
|
||||
req.session.advertisingId = advertisingId
|
||||
const item = await AdvertisingTypeModel.findOne({ name: itemName })
|
||||
const user = await UserModel.findById(userId)
|
||||
|
||||
if (item.name === 'free' && item.price === 0) {
|
||||
if (user.daily_free_request > 0) {
|
||||
user.daily_free_request -= 1
|
||||
await user.save()
|
||||
const project = await AdvertisingModel.findById(advertisingId)
|
||||
if (!project) {
|
||||
res.status(404).send('Advertising not found')
|
||||
return
|
||||
}
|
||||
project.payment_status = 'done' // Set project status to 'done'
|
||||
project.status = 'paid' // Set project status to 'done'
|
||||
await project.save()
|
||||
res.status(200).json({ message: 'بیلبورد رایگان با موفقیت ایجاد شد', advertisingId, type: 'free' })
|
||||
} else {
|
||||
res.status(403).json({ message: 'شما قبلاً از بیلبورد رایگان این ماه استفاده کردهاید.' })
|
||||
}
|
||||
} else {
|
||||
const response = await axios.post('https://www.zarinpal.com/pg/rest/WebGate/PaymentRequest.json', {
|
||||
MerchantID: process.env.ZARINPAL_MERCHANT_ID,
|
||||
Amount: showDiscount === true || showDiscount === 'true' ? Number(price + 20000) : Number(price),
|
||||
Description: `پرداخت برای سفارش شماره ${advertisingId}`,
|
||||
CallbackURL: `${process.env.APP_SITE_CallBack}/advertising/payment-web?advertisingId=${advertisingId}&itemName=${itemName}&userId=${userId}&showDiscount=${showDiscount}` // Assuming your backend URL for handling payment callback
|
||||
})
|
||||
const data = response.data
|
||||
if (data.Status === 100) {
|
||||
// Payment request was successful
|
||||
const authority = data.Authority // The payment authority (شناسه پرداخت)
|
||||
res.status(200).json({ authority })
|
||||
} else {
|
||||
// Payment request failed
|
||||
console.error('Error occurred while initiating payment:', data)
|
||||
res.status(500).json({ error: 'Error occurred while initiating payment' })
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Error occurred while getting price from database or sending the request
|
||||
console.error('Error occurred:', error)
|
||||
res.status(500).json({ error: 'Internal server error' })
|
||||
}
|
||||
}
|
||||
const handleAdvertisingPaymentCallbackWeb = async (req, res) => {
|
||||
try {
|
||||
// console.log(req.query)
|
||||
// Extract payment status and authority from ZarinPal callback
|
||||
const status = req.query.Status
|
||||
const authority = req.query.Authority
|
||||
const advertisingId = req.query.advertisingId // Get project ID from session
|
||||
const itemName = req.query.itemName // Get project ID from session
|
||||
const userId = req.query.userId // Get project ID from session
|
||||
const showDiscount = req.query.showDiscount // Get project ID from session
|
||||
// Clear project ID from session
|
||||
// Query ZarinPal API to verify payment status
|
||||
|
||||
const verificationUrl = 'https://www.zarinpal.com/pg/rest/WebGate/PaymentVerification.json'
|
||||
const price = await getAdvertisingPriceFromDatabase(itemName) // Get price from database
|
||||
const verificationResponse = await axios.post(verificationUrl, {
|
||||
MerchantID: apiKey,
|
||||
Authority: authority,
|
||||
Amount: showDiscount === true || showDiscount === 'true' ? Number(price + 20000) : Number(price)
|
||||
})
|
||||
|
||||
const verificationData = verificationResponse.data
|
||||
if (verificationData.Status === 100) {
|
||||
const payment = new PaymentModel({
|
||||
amount: showDiscount === true || showDiscount === 'true' ? Number(price + 20000) : Number(price),
|
||||
status: 'successful',
|
||||
authority,
|
||||
user_id: userId, // فرضاً شما از نوع میانافزارهای مدیریت کاربر استفاده میکنید و اطلاعات کاربر را از طریق `req.user` در دسترس دارید
|
||||
advertising_id: advertisingId,
|
||||
type: 'advertising',
|
||||
installment_step: null
|
||||
// دیگر اطلاعات مورد نیاز برای ثبت پرداخت
|
||||
})
|
||||
await payment.save()
|
||||
|
||||
// Payment verification is successful
|
||||
// Now, update project status to 'done' or desired status
|
||||
const advertising = await AdvertisingModel.findById(advertisingId)
|
||||
if (!advertising) {
|
||||
res.status(404).send('Advertising not found')
|
||||
return
|
||||
}
|
||||
advertising.payment_status = 'done' // Set advertising status to 'done'
|
||||
advertising.status = 'paid' // Set advertising status to 'done'
|
||||
await advertising.save()
|
||||
|
||||
// Send event based on payment status
|
||||
if ('eventEmitter' in req.app) {
|
||||
if (status === 'OK') {
|
||||
// Payment is successful
|
||||
// Emit an event to be listened to in the frontend
|
||||
// Example event name: 'paymentSuccess'
|
||||
// Example data: { message: 'Payment successful' }
|
||||
// You can customize the event name and data as needed
|
||||
req.app.get('eventEmitter').emit('paymentSuccess', { message: 'Payment successful' })
|
||||
} else {
|
||||
// Payment is canceled or failed
|
||||
// Emit an event to be listened to in the frontend
|
||||
// Example event name: 'paymentFailed'
|
||||
// Example data: { message: 'Payment canceled or failed' }
|
||||
// You can customize the event name and data as needed
|
||||
req.app.get('eventEmitter').emit('paymentFailed', { message: 'Payment canceled or failed' })
|
||||
}
|
||||
} else {
|
||||
console.error('Error: eventEmitter is not defined or not properly configured.')
|
||||
}
|
||||
|
||||
// Redirect to the callback URL with the advertising ID
|
||||
res.redirect(`https://modstagram.com/billboards/payment/success?projectId=${advertisingId}&price=${showDiscount === true || showDiscount === 'true' ? Number(price + 20000) : Number(price)}&type=advertising&showDiscount=${showDiscount}`)
|
||||
} else {
|
||||
// Payment verification failed
|
||||
const payment = new PaymentModel({
|
||||
amount: showDiscount ? Number(price + 20000) : Number(price),
|
||||
status: 'failed',
|
||||
authority,
|
||||
user_id: userId, // فرضاً شما از نوع میانافزارهای مدیریت کاربر استفاده میکنید و اطلاعات کاربر را از طریق `req.user` در دسترس دارید
|
||||
advertising_id: advertisingId,
|
||||
type: 'advertising'
|
||||
// دیگر اطلاعات مورد نیاز برای ثبت پرداخت
|
||||
})
|
||||
console.log('ss')
|
||||
|
||||
await payment.save()
|
||||
res.redirect(`https://modstagram.com/billboards/payment/failed?projectId=${advertisingId}&price=${showDiscount === true || showDiscount === 'true' ? Number(price + 20000) : Number(price)}&type=advertising&showDiscount=${showDiscount}`)
|
||||
}
|
||||
} catch (error) {
|
||||
// Error occurred while verifying payment
|
||||
console.error('Error occurred:', error)
|
||||
res.status(500).send('Internal server error')
|
||||
}
|
||||
}
|
||||
|
||||
const republishAdvertisingPaymentWeb = async (req, res) => {
|
||||
try {
|
||||
const token = req.header('Authorization').split(' ')[1]
|
||||
if (!token) return res.status(401).send('Access Denied')
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const decodedToken = jwt.verify(token, process.env.APP_SECRET)
|
||||
const userId = decodedToken.id
|
||||
const itemName = req.body.item_name // Get item name from request body
|
||||
const price = await getAdvertisingPriceFromDatabase(itemName) // Get price from database
|
||||
const advertisingId = req.body.advertisingId // Get project ID from request body
|
||||
const showDiscount = req.body.showDiscount
|
||||
// Save project ID for later use in callback URL
|
||||
req.session.advertisingId = advertisingId
|
||||
const item = await AdvertisingTypeModel.findOne({ name: itemName })
|
||||
const user = await UserModel.findById(userId)
|
||||
|
||||
if (item.name === 'free' && item.price === 0) {
|
||||
if (user.daily_free_request > 0) {
|
||||
user.daily_free_request -= 1
|
||||
await user.save()
|
||||
const project = await AdvertisingModel.findById(advertisingId)
|
||||
if (!project) {
|
||||
res.status(404).send('Project not found')
|
||||
return
|
||||
}
|
||||
project.payment_status = 'done' // Set project status to 'done'
|
||||
project.status = 'paid' // Set project status to 'done'
|
||||
await project.save()
|
||||
res.status(200).json({ message: 'پروژه رایگان با موفقیت ایجاد شد', advertisingId, type: 'free' })
|
||||
} else {
|
||||
res.status(403).json({ message: 'شما قبلاً از درخواست رایگان امروز استفاده کردهاید.' })
|
||||
}
|
||||
} else {
|
||||
const response = await axios.post('https://www.zarinpal.com/pg/rest/WebGate/PaymentRequest.json', {
|
||||
MerchantID: apiKey,
|
||||
Amount: showDiscount === true || showDiscount === 'true' ? Number(((price + 20000) * 70) / 100) : Number(((price) * 70) / 100),
|
||||
Description: `پرداخت برای سفارش شماره ${advertisingId}`,
|
||||
CallbackURL: `${process.env.APP_URL}/advertising/republish-verify-payment-web?advertisingId=${advertisingId}&itemName=${itemName}&userId=${userId}&showDiscount=${showDiscount}` // Assuming your backend URL for handling payment callback
|
||||
})
|
||||
const data = response.data
|
||||
if (data.Status === 100) {
|
||||
// Payment request was successful
|
||||
const authority = data.Authority // The payment authority (شناسه پرداخت)
|
||||
res.status(200).json({ authority })
|
||||
} else {
|
||||
// Payment request failed
|
||||
console.error('Error occurred while initiating payment:', data)
|
||||
res.status(500).json({ error: 'Error occurred while initiating payment' })
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Error occurred while getting price from database or sending the request
|
||||
console.error('Error occurred:', error)
|
||||
res.status(500).json({ error: 'Internal server error' })
|
||||
}
|
||||
}
|
||||
const handleAdvertisingRepublishPaymentCallbackWeb = async (req, res) => {
|
||||
try {
|
||||
// console.log(req.query)
|
||||
// Extract payment status and authority from ZarinPal callback
|
||||
const status = req.query.Status
|
||||
const authority = req.query.Authority
|
||||
const advertisingId = req.query.advertisingId // Get project ID from session
|
||||
const itemName = req.query.itemName // Get project ID from session
|
||||
const userId = req.query.userId // Get project ID from session
|
||||
const showDiscount = req.query.showDiscount // Get project ID from session
|
||||
// Clear project ID from session
|
||||
// Query ZarinPal API to verify payment status
|
||||
const verificationUrl = 'https://www.zarinpal.com/pg/rest/WebGate/PaymentVerification.json'
|
||||
const price = await getAdvertisingPriceFromDatabase(itemName) // Get price from database
|
||||
const verificationResponse = await axios.post(verificationUrl, {
|
||||
MerchantID: apiKey,
|
||||
Authority: authority,
|
||||
Amount: showDiscount === true || showDiscount === 'true' ? Number(((price + 20000) * 70) / 100) : Number(((price) * 70) / 100)
|
||||
})
|
||||
|
||||
const verificationData = verificationResponse.data
|
||||
if (verificationData.Status === 100) {
|
||||
const payment = new PaymentModel({
|
||||
amount: showDiscount === true || showDiscount === 'true' ? Number(((price + 20000) * 70) / 100) : Number(((price) * 70) / 100),
|
||||
status: 'successful',
|
||||
authority,
|
||||
user_id: userId, // فرضاً شما از نوع میانافزارهای مدیریت کاربر استفاده میکنید و اطلاعات کاربر را از طریق `req.user` در دسترس دارید
|
||||
advertising_id: advertisingId,
|
||||
type: 'advertising',
|
||||
installment_step: null
|
||||
// دیگر اطلاعات مورد نیاز برای ثبت پرداخت
|
||||
})
|
||||
await payment.save()
|
||||
|
||||
// Payment verification is successful
|
||||
// Now, update project status to 'done' or desired status
|
||||
const advertising = await AdvertisingModel.findById(advertisingId)
|
||||
if (!advertising) {
|
||||
res.status(404).send('Advertising not found')
|
||||
return
|
||||
}
|
||||
advertising.payment_status = 'done' // Set advertising status to 'done'
|
||||
advertising.status = 'accepted' // Set advertising status to 'done'
|
||||
advertising.acceptedAt = new Date()
|
||||
await advertising.save()
|
||||
|
||||
// Send event based on payment status
|
||||
if ('eventEmitter' in req.app) {
|
||||
if (status === 'OK') {
|
||||
// Payment is successful
|
||||
// Emit an event to be listened to in the frontend
|
||||
// Example event name: 'paymentSuccess'
|
||||
// Example data: { message: 'Payment successful' }
|
||||
// You can customize the event name and data as needed
|
||||
req.app.get('eventEmitter').emit('paymentSuccess', { message: 'Payment successful' })
|
||||
} else {
|
||||
// Payment is canceled or failed
|
||||
// Emit an event to be listened to in the frontend
|
||||
// Example event name: 'paymentFailed'
|
||||
// Example data: { message: 'Payment canceled or failed' }
|
||||
// You can customize the event name and data as needed
|
||||
req.app.get('eventEmitter').emit('paymentFailed', { message: 'Payment canceled or failed' })
|
||||
}
|
||||
} else {
|
||||
console.error('Error: eventEmitter is not defined or not properly configured.')
|
||||
}
|
||||
|
||||
// Redirect to the callback URL with the advertising ID
|
||||
res.redirect(`https://modstagram.com/billboards/payment/success?projectId=${advertisingId}&price=${showDiscount === true || showDiscount === 'true' ? Number(((price + 20000) * 70) / 100) : Number(((price) * 70) / 100)}&type=advertising-republish&showDiscount=${showDiscount}`)
|
||||
} else {
|
||||
// Payment verification failed
|
||||
const payment = new PaymentModel({
|
||||
amount: showDiscount === true || showDiscount === 'true' ? Number(((price + 20000) * 70) / 100) : Number(((price) * 70) / 100),
|
||||
status: 'failed',
|
||||
authority,
|
||||
user_id: userId, // فرضاً شما از نوع میانافزارهای مدیریت کاربر استفاده میکنید و اطلاعات کاربر را از طریق `req.user` در دسترس دارید
|
||||
advertising_id: advertisingId,
|
||||
type: 'advertising'
|
||||
// دیگر اطلاعات مورد نیاز برای ثبت پرداخت
|
||||
})
|
||||
await payment.save()
|
||||
res.redirect(`https://modstagram.com/billboards/payment/failed?projectId=${advertisingId}&price=${showDiscount === true || showDiscount === 'true' ? Number(((price + 20000) * 70) / 100) : Number(((price) * 70) / 100)}&type=advertising-republish&showDiscount=${showDiscount}`)
|
||||
}
|
||||
} catch (error) {
|
||||
// Error occurred while verifying payment
|
||||
console.error('Error occurred:', error)
|
||||
res.status(500).send('Internal server error')
|
||||
}
|
||||
}
|
||||
// const initiateOfferPaymentWeb = async (req, res) => {
|
||||
// try {
|
||||
// const token = req.header('Authorization')?.split(' ')[1];
|
||||
// if (!token) {
|
||||
// return res.status(401).json({ error: 'Access Denied: No token provided' });
|
||||
// }
|
||||
|
||||
// let decodedToken;
|
||||
// try {
|
||||
// decodedToken = jwt.verify(token, process.env.APP_SECRET);
|
||||
// } catch (err) {
|
||||
// return res.status(401).json({ error: 'Invalid token' });
|
||||
// }
|
||||
|
||||
// const userId = decodedToken.id;
|
||||
// const { receiverId, offerType } = req.body;
|
||||
|
||||
// // اعتبارسنجی ورودیها
|
||||
// if (!receiverId || !offerType) {
|
||||
// return res.status(400).json({ error: 'receiverId and offerType are required' });
|
||||
// }
|
||||
|
||||
// const user = await UserModel.findById(userId);
|
||||
// if (!user) {
|
||||
// return res.status(404).json({ error: 'User not found' });
|
||||
// }
|
||||
|
||||
// const receiverUser = await UserModel.findById(receiverId);
|
||||
// if (!receiverUser) {
|
||||
// return res.status(404).json({ error: 'Receiver not found' });
|
||||
// }
|
||||
|
||||
// let price;
|
||||
// if (user.monthly_free_offer > 0 && offerType === 'free') {
|
||||
// price = 0;
|
||||
// user.monthly_free_offer -= 1;
|
||||
// await user.save();
|
||||
// } else {
|
||||
// price = await getOfferPriceFromDatabase(offerType);
|
||||
// }
|
||||
|
||||
// if (price === 0) {
|
||||
// const offer = new OfferModel({
|
||||
// sender: userId,
|
||||
// receiver: receiverId,
|
||||
// transaction_id: null,
|
||||
// });
|
||||
// await offer.save();
|
||||
// return res.status(200).json({ message: 'آفر رایگان با موفقیت ثبت شد', offerId: offer._id, type: 'free' });
|
||||
// }
|
||||
// console.log('🔹 Initiating ZarinPal Payment');
|
||||
// console.log('MerchantID:', apiKey);
|
||||
// console.log('Amount:', Number(price * 10));
|
||||
// console.log('Description:', `پرداخت برای ارسال آفر به ${receiverUser.first_name}`);
|
||||
// console.log('CallbackURL:', `${process.env.APP_URL}/offers/payment-web?receiverId=${receiverId}&offerType=${offerType}&userId=${userId}`);
|
||||
|
||||
// const ZARINPAL_URL = 'https://api.zarinpal.com/pg/v4/payment/request.json';
|
||||
// //
|
||||
// const response = await axios.post(ZARINPAL_URL, {
|
||||
// merchant_id: process.env.ZARINPAL_MERCHANT_ID, // ❌ MerchantID نیست!
|
||||
// amount: Number(price), // ✅ به ریال
|
||||
// description: `پرداخت برای ارسال آفر به ${receiverUser.first_name}`,
|
||||
// callback_url: `${process.env.APP_SITE_CallBack}/offer/payment-web?receiverId=${receiverId}&offerType=${offerType}&userId=${userId}`,
|
||||
// }, { headers: { 'Content-Type': 'application/json' } });
|
||||
|
||||
// const result = response.data.data; // ✅ data.data
|
||||
|
||||
// if (result.code === 100) { // ✅ code === 100
|
||||
// return res.status(200).json({
|
||||
// authority: result.authority,
|
||||
// paymentUrl: `https://www.zarinpal.com/pg/StartPay/${result.authority}`
|
||||
// });
|
||||
// } else {
|
||||
// console.error('ZarinPal error:', data);
|
||||
// return res.status(500).json({ error: `Failed to initiate payment: ZarinPal Status ${data.Status}` });
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('❌ Error in initiateOfferPaymentWeb:', error.message, error.stack);
|
||||
// return res.status(500).json({ error: error.message || 'Internal server error' });
|
||||
// }
|
||||
// }
|
||||
const initiateOfferPaymentWeb = async (req, res) => {
|
||||
try {
|
||||
const token = req.header('Authorization')?.split(' ')[1];
|
||||
if (!token) return res.status(401).json({ error: 'No token' });
|
||||
|
||||
const decoded = jwt.verify(token, process.env.APP_SECRET);
|
||||
const userId = decoded.id;
|
||||
|
||||
const { receiverId, offerType } = req.body;
|
||||
if (!receiverId || !offerType)
|
||||
return res.status(400).json({ error: 'Invalid data' });
|
||||
|
||||
const user = await UserModel.findById(userId);
|
||||
const receiver = await UserModel.findById(receiverId);
|
||||
if (!user || !receiver)
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
|
||||
let price = await getOfferPriceFromDatabase(offerType); // ✅ ریال
|
||||
|
||||
// 🎁 free offer
|
||||
if (offerType === 'free' && user.monthly_free_offer > 0) {
|
||||
const offer = await OfferModel.create({
|
||||
sender: userId,
|
||||
receiver: receiverId,
|
||||
transaction_id: null,
|
||||
});
|
||||
|
||||
user.monthly_free_offer -= 1;
|
||||
await user.save();
|
||||
|
||||
return res.json({
|
||||
type: 'free',
|
||||
offerId: offer._id,
|
||||
});
|
||||
}
|
||||
|
||||
const amount = Number(price) * 10; // ✅ ریال – بدون ×10
|
||||
const callbackUrl = `https://api.modstagram.com/api/v1/offers/payment-web?receiverId=${receiverId}&offerType=${offerType}&userId=${userId}`;
|
||||
|
||||
const zarinpalRes = await axios.post(
|
||||
'https://api.zarinpal.com/pg/v4/payment/request.json',
|
||||
{
|
||||
merchant_id:"c7c41e8a-918f-4741-bcd5-58f3bc51db73",
|
||||
amount,
|
||||
description: `ارسال آفر به ${receiver.first_name}`,
|
||||
callback_url: callbackUrl
|
||||
|
||||
// callback_url: `${process.env.APP_SITE_CallBack}/offers/payment-web?receiverId=${receiverId}&offerType=${offerType}&userId=${userId}`,
|
||||
},
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
|
||||
// console.log(`${process.env.APP_SITE_CallBack}/offers/payment-web?receiverId=${receiverId}&offerType=${offerType}&userId=${userId}`);
|
||||
|
||||
|
||||
const result = zarinpalRes.data.data;
|
||||
console.log(result);
|
||||
console.log("ZarinPal Callback URL:", callbackUrl);
|
||||
console.log("Initiate payment request:", { userId, receiverId, offerType, price });
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (result.code === 100) {
|
||||
return res.json({
|
||||
authority: result.authority,
|
||||
paymentUrl: `https://www.zarinpal.com/pg/StartPay/${result.authority}`,
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(500).json({ error: 'ZarinPal error' });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// try {
|
||||
// const { receiverId, offerType, userId, Authority, Status } = req.query;
|
||||
|
||||
// // ❗ چک اولیه
|
||||
// if (Status !== 'OK' || !Authority) {
|
||||
// return res.status(400).json({
|
||||
// success: false,
|
||||
// message: 'پرداخت ناموفق یا لغو شد'
|
||||
// });
|
||||
// }
|
||||
|
||||
// if (!receiverId || !offerType || !userId) {
|
||||
// return res.status(400).json({
|
||||
// success: false,
|
||||
// message: 'پارامترهای ناقص'
|
||||
// });
|
||||
// }
|
||||
|
||||
// // پیدا کردن کاربرها
|
||||
// const user = await UserModel.findById(userId);
|
||||
// const receiverUser = await UserModel.findById(receiverId);
|
||||
|
||||
// if (!user || !receiverUser) {
|
||||
// return res.status(404).json({
|
||||
// success: false,
|
||||
// message: 'کاربر یافت نشد'
|
||||
// });
|
||||
// }
|
||||
|
||||
// const price = await getOfferPriceFromDatabase(offerType);
|
||||
|
||||
// const verifyResponse = await axios.post(
|
||||
// 'https://api.zarinpal.com/pg/v4/payment/verify.json',
|
||||
// {
|
||||
// merchant_id: process.env.ZARINPAL_MERCHANT_ID, // یا MERCHENT_CODE
|
||||
// authority: Authority,
|
||||
// amount: price, // به ریال
|
||||
// },
|
||||
// { headers: { 'Content-Type': 'application/json' } }
|
||||
// );
|
||||
|
||||
// const verifyData = verifyResponse.data.data;
|
||||
|
||||
// if (verifyData.code === 100) {
|
||||
// // ✅ پرداخت موفق
|
||||
// const payment = new PaymentModel({
|
||||
// amount: Number(price),
|
||||
// status: 'successful',
|
||||
// authority: Authority,
|
||||
// ref_id: verifyData.ref_id,
|
||||
// user_id: userId,
|
||||
// type: 'offer',
|
||||
// });
|
||||
// await payment.save();
|
||||
|
||||
// const offer = new OfferModel({
|
||||
// sender: userId,
|
||||
// receiver: receiverId,
|
||||
// transaction_id: payment._id,
|
||||
// });
|
||||
// await offer.save();
|
||||
|
||||
// // نوتیفیکیشن و SMS (همون کد قبلی)
|
||||
// const notification = new NotificationModel({
|
||||
// user_id: receiverId,
|
||||
// project_post_id: offer._id,
|
||||
// type: 'new_offer',
|
||||
// title: 'درخواست همکاری جدید',
|
||||
// description: `${user.first_name} یک درخواست همکاری برای شما ارسال کرده است`,
|
||||
// });
|
||||
// await notification.save();
|
||||
|
||||
// const data = JSON.stringify({
|
||||
// mobile: receiverUser?.mobile,
|
||||
// templateId: '569006',
|
||||
// parameters: [
|
||||
// { name: 'FIRSTNAME', value: receiverUser?.first_name },
|
||||
// { name: 'LASTNAME', value: receiverUser?.last_name },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// const config = {
|
||||
// method: 'post',
|
||||
// url: 'https://api.sms.ir/v1/send/verify',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// Accept: 'text/plain',
|
||||
// 'x-api-key': process.env.SMS_VERIFY_KEY,
|
||||
// },
|
||||
// data,
|
||||
// };
|
||||
|
||||
// await axios(config).catch((error) => {
|
||||
// console.error('SMS error:', error.message);
|
||||
// });
|
||||
|
||||
// if ('eventEmitter' in req.app && status === 'OK') {
|
||||
// req.app.get('eventEmitter').emit('paymentSuccess', { message: 'Payment successful' });
|
||||
// } else {
|
||||
// req.app.get('eventEmitter')?.emit('paymentFailed', { message: 'Payment canceled or failed' });
|
||||
// }
|
||||
|
||||
// res.redirect(`https://modstagram.com/offer/payment/success?userId=${userId}`);
|
||||
|
||||
// return res.status(200).json({
|
||||
// success: true,
|
||||
// message: 'پرداخت و آفر با موفقیت ثبت شد',
|
||||
// ref_id: verifyData.ref_id,
|
||||
// offerId: offer._id
|
||||
// });
|
||||
// } else {
|
||||
// // پرداخت ناموفق
|
||||
// const payment = new PaymentModel({
|
||||
// amount: Number(price),
|
||||
// status: 'failed',
|
||||
// authority: Authority,
|
||||
// user_id: userId,
|
||||
// type: 'offer',
|
||||
// });
|
||||
// await payment.save();
|
||||
// res.redirect(`https://modstagram.com/offer/payment/failed?userId=${userId}`);
|
||||
// return res.status(400).json({
|
||||
// success: false,
|
||||
// message: `خطا در تأیید پرداخت: ${verifyData.code}`
|
||||
// });
|
||||
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('❌ Callback Error:', error.message);
|
||||
// return res.status(500).json({
|
||||
// success: false,
|
||||
// message: 'خطای سرور'
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
|
||||
const handleOfferPaymentCallback = async (req, res) => {
|
||||
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
||||
|
||||
console.log('🔔 CALLBACK QUERY:', req.query);
|
||||
|
||||
try {
|
||||
const { Authority, Status, receiverId, offerType, userId } = req.query;
|
||||
|
||||
if (Status !== 'OK')
|
||||
return res.redirect(`${process.env.APP_SITE}/offer/payment/failed`);
|
||||
|
||||
const price = await getOfferPriceFromDatabase(offerType); // ریال
|
||||
const amount = Number(price) * 10;
|
||||
|
||||
const verify = await axios.post(
|
||||
'https://api.zarinpal.com/pg/v4/payment/verify.json',
|
||||
{
|
||||
merchant_id: "c7c41e8a-918f-4741-bcd5-58f3bc51db73",
|
||||
authority: Authority,
|
||||
amount,
|
||||
},
|
||||
{ headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
|
||||
const data = verify.data.data;
|
||||
console.log('🔔payment:', data.code);
|
||||
if (data.code === 100) {
|
||||
const payment = await PaymentModel.create({
|
||||
amount : (amount / 10),
|
||||
status: 'successful',
|
||||
authority: Authority,
|
||||
ref_id: data.ref_id,
|
||||
user_id: userId,
|
||||
type: 'offer',
|
||||
});
|
||||
|
||||
console.log('🔔payment:', payment);
|
||||
|
||||
const offer = await OfferModel.create({
|
||||
sender: userId,
|
||||
receiver: receiverId,
|
||||
transaction_id: payment._id,
|
||||
});
|
||||
|
||||
return res.redirect(
|
||||
`${process.env.APP_SITE}/offer/payment/success?offerId=${offer._id}`
|
||||
);
|
||||
}
|
||||
|
||||
return res.redirect(`${process.env.APP_SITE}/offer/payment/failed`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return res.redirect(`${process.env.APP_SITE}/offer/payment/failed`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
initiatePaymentWeb,
|
||||
handlePaymentCallbackWeb,
|
||||
paymentRequestAcceptWeb,
|
||||
initiateAdvertisingPaymentWeb,
|
||||
handleAdvertisingPaymentCallbackWeb,
|
||||
republishAdvertisingPaymentWeb,
|
||||
handleAdvertisingRepublishPaymentCallbackWeb,
|
||||
initiateOfferPaymentWeb,
|
||||
handleOfferPaymentCallback,
|
||||
};
|
||||
Reference in New Issue
Block a user