소스 검색

ci: add precommit and semantic commit workflow

* ci: add commitlint config file

* ci: add precommit config

* style: lint code
pull/3/head
phot0n 2 년 전
부모
커밋
405de74f80
18개의 변경된 파일286개의 추가작업 그리고 139개의 파일을 삭제
  1. +1
    -1
      .github/workflows/ci.yml
  2. +54
    -0
      .github/workflows/linter.yml
  3. +50
    -0
      .pre-commit-config.yaml
  4. +25
    -0
      commitlint.config.js
  5. +2
    -7
      payments/config/desktop.py
  6. +1
    -0
      payments/config/docs.py
  7. +2
    -2
      payments/hooks.py
  8. +3
    -3
      payments/overrides/payment_webform.py
  9. +3
    -2
      payments/payment_gateways/doctype/braintree_settings/braintree_settings.py
  10. +21
    -10
      payments/payment_gateways/doctype/paypal_settings/paypal_settings.py
  11. +15
    -7
      payments/payment_gateways/doctype/paytm_settings/paytm_settings.py
  12. +2
    -5
      payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py
  13. +1
    -3
      payments/templates/pages/braintree_checkout.py
  14. +4
    -4
      payments/templates/pages/paytm_checkout.py
  15. +3
    -1
      payments/templates/pages/razorpay_checkout.py
  16. +11
    -4
      payments/templates/pages/stripe_checkout.py
  17. +4
    -7
      payments/utils/__init__.py
  18. +84
    -83
      payments/utils/utils.py

+ 1
- 1
.github/workflows/ci.yml 파일 보기

@@ -1,5 +1,5 @@

name: CI
name: Server

on:
push:


+ 54
- 0
.github/workflows/linter.yml 파일 보기

@@ -0,0 +1,54 @@
name: Linter

on:
pull_request:
workflow_dispatch:
push:
branches: [ develop ]

permissions:
contents: read

concurrency:
group: commitcheck-frappe-${{ github.event.number }}
cancel-in-progress: true

jobs:
commit-lint:
name: 'Semantic Commits'
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 200
- uses: actions/setup-node@v3
with:
node-version: 16
check-latest: true

- name: Check commit titles
run: |
npm install @commitlint/cli @commitlint/config-conventional
npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }}

linter:
name: 'Frappe Linter'
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'

steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- uses: pre-commit/action@v3.0.0

- name: Download Semgrep rules
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules

- name: Run Semgrep rules
run: |
pip install semgrep==0.97.0
semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness

+ 50
- 0
.pre-commit-config.yaml 파일 보기

@@ -0,0 +1,50 @@
exclude: 'node_modules|.git'
default_stages: [commit]
fail_fast: false


repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: trailing-whitespace
files: "frappe.*"
exclude: ".*json$|.*txt$|.*csv|.*md|.*svg"
- id: check-yaml
- id: no-commit-to-branch
args: ['--branch', 'develop']
- id: check-merge-conflict
- id: check-ast
- id: check-json
- id: check-toml
- id: check-yaml
- id: debug-statements

- repo: https://github.com/asottile/pyupgrade
rev: v2.34.0
hooks:
- id: pyupgrade
args: ['--py310-plus']

- repo: https://github.com/adityahase/black
rev: 9cb0a69f4d0030cdf687eddf314468b39ed54119
hooks:
- id: black
additional_dependencies: ['click==8.0.4']

- repo: https://github.com/timothycrosley/isort
rev: 5.9.1
hooks:
- id: isort

- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8
additional_dependencies: ['flake8-bugbear',]
args: ['--config', '.github/helper/flake8.conf']

ci:
autoupdate_schedule: weekly
skip: []
submodules: false

+ 25
- 0
commitlint.config.js 파일 보기

@@ -0,0 +1,25 @@
module.exports = {
parserPreset: 'conventional-changelog-conventionalcommits',
rules: {
'subject-empty': [2, 'never'],
'type-case': [2, 'always', 'lower-case'],
'type-empty': [2, 'never'],
'type-enum': [
2,
'always',
[
'build',
'chore',
'ci',
'docs',
'feat',
'fix',
'perf',
'refactor',
'revert',
'style',
'test',
],
],
},
};

+ 2
- 7
payments/config/desktop.py 파일 보기

@@ -1,10 +1,5 @@
from frappe import _


def get_data():
return [
{
"module_name": "Payments",
"type": "module",
"label": _("Payments")
}
]
return [{"module_name": "Payments", "type": "module", "label": _("Payments")}]

+ 1
- 0
payments/config/docs.py 파일 보기

@@ -6,5 +6,6 @@ Configuration for docs
# headline = "App that does everything"
# sub_heading = "Yes, you got that right the first time, everything"


def get_context(context):
context.brand_html = "Payments"

+ 2
- 2
payments/hooks.py 파일 보기

@@ -42,7 +42,7 @@ app_license = "MIT"

# website user home page (by Role)
# role_home_page = {
# "Role": "home_page"
# "Role": "home_page"
# }

# Generators
@@ -107,7 +107,7 @@ override_doctype_class = {
# "on_update": "method",
# "on_cancel": "method",
# "on_trash": "method"
# }
# }
# }

# Scheduled Tasks


+ 3
- 3
payments/overrides/payment_webform.py 파일 보기

@@ -25,12 +25,13 @@ class PaymentWebForm(WebForm):
if getattr(self, "accept_payment", False):
controller = get_payment_gateway_controller(self.payment_gateway)

title = "Payment for {0} {1}".format(doc.doctype, doc.name)
title = f"Payment for {doc.doctype} {doc.name}"
amount = self.amount
if self.amount_based_on_field:
amount = doc.get(self.amount_field)

from decimal import Decimal

if amount is None or Decimal(amount) <= 0:
return frappe.utils.get_url(self.success_url or self.route)

@@ -44,14 +45,13 @@ class PaymentWebForm(WebForm):
"payer_name": frappe.utils.get_fullname(frappe.session.user),
"order_id": doc.name,
"currency": self.currency,
"redirect_to": frappe.utils.get_url(self.success_url or self.route)
"redirect_to": frappe.utils.get_url(self.success_url or self.route),
}

# Redirect the user to this url
return controller.get_payment_url(**payment_details)



@frappe.whitelist(allow_guest=True)
@rate_limit(key="web_form", limit=5, seconds=60, methods=["POST"])
def accept(web_form, data, docname=None, for_payment=False):


+ 3
- 2
payments/payment_gateways/doctype/braintree_settings/braintree_settings.py 파일 보기

@@ -4,7 +4,6 @@
from urllib.parse import urlencode

import braintree

import frappe
from frappe import _
from frappe.integrations.utils import create_request_log
@@ -225,7 +224,9 @@ class BraintreeSettings(Document):
if result.is_success:
self.integration_request.db_set("status", "Completed", update_modified=False)
self.flags.status_changed_to = "Completed"
self.integration_request.db_set("output", result.transaction.status, update_modified=False)
self.integration_request.db_set(
"output", result.transaction.status, update_modified=False
)

elif result.transaction:
self.integration_request.db_set("status", "Failed", update_modified=False)


+ 21
- 10
payments/payment_gateways/doctype/paypal_settings/paypal_settings.py 파일 보기

@@ -65,9 +65,8 @@ More Details:
import json
from urllib.parse import urlencode

import pytz

import frappe
import pytz
from frappe import _
from frappe.integrations.utils import create_request_log, make_post_request
from frappe.model.document import Document
@@ -75,7 +74,9 @@ from frappe.utils import call_hook_method, cint, get_datetime, get_url

from payments.utils import create_payment_gateway

api_path = "/api/method/payments.payment_gateways.doctype.paypal_settings.paypal_settings"
api_path = (
"/api/method/payments.payment_gateways.doctype.paypal_settings.paypal_settings"
)


class PayPalSettings(Document):
@@ -176,7 +177,9 @@ class PayPalSettings(Document):
response = self.execute_set_express_checkout(**kwargs)

if self.paypal_sandbox or self.use_sandbox:
return_url = "https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}"
return_url = (
"https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}"
)
else:
return_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token={0}"

@@ -212,7 +215,9 @@ class PayPalSettings(Document):
response = make_post_request(url, data=params.encode("utf-8"))

if response.get("ACK")[0] != "Success":
frappe.throw(_("Looks like something is wrong with this site's Paypal configuration."))
frappe.throw(
_("Looks like something is wrong with this site's Paypal configuration.")
)

return response

@@ -294,7 +299,9 @@ def get_express_checkout_details(token):
)

frappe.local.response["type"] = "redirect"
frappe.local.response["location"] = get_redirect_uri(doc, token, response.get("PAYERID")[0])
frappe.local.response["location"] = get_redirect_uri(
doc, token, response.get("PAYERID")[0]
)

except Exception:
frappe.log_error(frappe.get_traceback())
@@ -360,7 +367,9 @@ def create_recurring_profile(token, payerid):
if data.get("subscription_id"):
if addons:
updating = True
manage_recurring_payment_profile_status(data["subscription_id"], "Cancel", params, url)
manage_recurring_payment_profile_status(
data["subscription_id"], "Cancel", params, url
)

params.update(
{
@@ -382,10 +391,12 @@ def create_recurring_profile(token, payerid):
"Completed" if data.get("starting_immediately") or updating else "Verified"
)

starts_at = get_datetime(subscription_details.get("start_date")) or frappe.utils.now_datetime()
starts_at = starts_at.replace(tzinfo=pytz.timezone(frappe.utils.get_time_zone())).astimezone(
pytz.utc
starts_at = (
get_datetime(subscription_details.get("start_date")) or frappe.utils.now_datetime()
)
starts_at = starts_at.replace(
tzinfo=pytz.timezone(frappe.utils.get_time_zone())
).astimezone(pytz.utc)

# "PROFILESTARTDATE": datetime.utcfromtimestamp(get_timestamp(starts_at)).isoformat()
params.update({"PROFILESTARTDATE": starts_at.isoformat()})


+ 15
- 7
payments/payment_gateways/doctype/paytm_settings/paytm_settings.py 파일 보기

@@ -4,15 +4,15 @@
import json
from urllib.parse import urlencode

import requests
from paytmchecksum import generateSignature, verifySignature

import frappe
import requests
from frappe import _
from frappe.integrations.utils import create_request_log
from frappe.model.document import Document
from frappe.utils import call_hook_method, cint, cstr, flt, get_request_site_address, get_url
from frappe.utils import (call_hook_method, cint, cstr, flt,
get_request_site_address, get_url)
from frappe.utils.password import get_decrypted_password
from paytmchecksum import generateSignature, verifySignature

from payments.utils import create_payment_gateway

@@ -46,7 +46,11 @@ def get_paytm_config():

paytm_config = frappe.db.get_singles_dict("Paytm Settings")
paytm_config.update(
dict(merchant_key=get_decrypted_password("Paytm Settings", "Paytm Settings", "merchant_key"))
dict(
merchant_key=get_decrypted_password(
"Paytm Settings", "Paytm Settings", "merchant_key"
)
)
)

if cint(paytm_config.staging):
@@ -110,7 +114,9 @@ def verify_transaction(**paytm_params):

if paytm_params and paytm_config and paytm_checksum:
# Verify checksum
is_valid_checksum = verifySignature(paytm_params, paytm_config.merchant_key, paytm_checksum)
is_valid_checksum = verifySignature(
paytm_params, paytm_config.merchant_key, paytm_checksum
)

if is_valid_checksum and paytm_params.get("RESPCODE") == "01":
verify_transaction_status(paytm_config, paytm_params["ORDERID"])
@@ -136,7 +142,9 @@ def verify_transaction_status(paytm_config, order_id):
post_data = json.dumps(paytm_params)
url = paytm_config.transaction_status_url

response = requests.post(url, data=post_data, headers={"Content-type": "application/json"}).json()
response = requests.post(
url, data=post_data, headers={"Content-type": "application/json"}
).json()
finalize_request(order_id, response)




+ 2
- 5
payments/payment_gateways/doctype/razorpay_settings/razorpay_settings.py 파일 보기

@@ -67,11 +67,8 @@ from urllib.parse import urlencode
import frappe
import razorpay
from frappe import _
from frappe.integrations.utils import (
create_request_log,
make_get_request,
make_post_request,
)
from frappe.integrations.utils import (create_request_log, make_get_request,
make_post_request)
from frappe.model.document import Document
from frappe.utils import call_hook_method, cint, get_timestamp, get_url



+ 1
- 3
payments/templates/pages/braintree_checkout.py 파일 보기

@@ -8,9 +8,7 @@ from frappe import _
from frappe.utils import flt

from payments.payment_gateways.doctype.braintree_settings.braintree_settings import (
get_client_token,
get_gateway_controller,
)
get_client_token, get_gateway_controller)

no_cache = 1



+ 4
- 4
payments/templates/pages/paytm_checkout.py 파일 보기

@@ -6,9 +6,7 @@ import frappe
from frappe import _

from payments.payment_gateways.doctype.paytm_settings.paytm_settings import (
get_paytm_config,
get_paytm_params,
)
get_paytm_config, get_paytm_params)


def get_context(context):
@@ -18,7 +16,9 @@ def get_context(context):
try:
doc = frappe.get_doc("Integration Request", frappe.form_dict["order_id"])

context.payment_details = get_paytm_params(json.loads(doc.data), doc.name, paytm_config)
context.payment_details = get_paytm_params(
json.loads(doc.data), doc.name, paytm_config
)

context.url = paytm_config.url



+ 3
- 1
payments/templates/pages/razorpay_checkout.py 파일 보기

@@ -59,7 +59,9 @@ def get_api_key():


@frappe.whitelist(allow_guest=True)
def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname, token):
def make_payment(
razorpay_payment_id, options, reference_doctype, reference_docname, token
):
data = {}

if isinstance(options, str):


+ 11
- 4
payments/templates/pages/stripe_checkout.py 파일 보기

@@ -6,7 +6,8 @@ import frappe
from frappe import _
from frappe.utils import cint, fmt_money

from payments.payment_gateways.doctype.stripe_settings.stripe_settings import get_gateway_controller
from payments.payment_gateways.doctype.stripe_settings.stripe_settings import \
get_gateway_controller

no_cache = 1

@@ -31,7 +32,9 @@ def get_context(context):
for key in expected_keys:
context[key] = frappe.form_dict[key]

gateway_controller = get_gateway_controller(context.reference_doctype, context.reference_docname)
gateway_controller = get_gateway_controller(
context.reference_doctype, context.reference_docname
)
context.publishable_key = get_api_key(context.reference_docname, gateway_controller)
context.image = get_header_image(context.reference_docname, gateway_controller)

@@ -48,14 +51,18 @@ def get_context(context):
else:
frappe.redirect_to_message(
_("Some information is missing"),
_("Looks like someone sent you to an incomplete URL. Please ask them to look into it."),
_(
"Looks like someone sent you to an incomplete URL. Please ask them to look into it."
),
)
frappe.local.flags.redirect_location = frappe.local.response.location
raise frappe.Redirect


def get_api_key(doc, gateway_controller):
publishable_key = frappe.db.get_value("Stripe Settings", gateway_controller, "publishable_key")
publishable_key = frappe.db.get_value(
"Stripe Settings", gateway_controller, "publishable_key"
)
if cint(frappe.form_dict.get("use_sandbox")):
publishable_key = frappe.conf.sandbox_publishable_key



+ 4
- 7
payments/utils/__init__.py 파일 보기

@@ -1,7 +1,4 @@
from payments.utils.utils import (
before_install,
create_payment_gateway,
delete_custom_fields,
get_payment_gateway_controller,
make_custom_fields,
)
from payments.utils.utils import (before_install, create_payment_gateway,
delete_custom_fields,
get_payment_gateway_controller,
make_custom_fields)

+ 84
- 83
payments/utils/utils.py 파일 보기

@@ -1,9 +1,9 @@
import click

import frappe
from frappe import _
from frappe.custom.doctype.custom_field.custom_field import \
create_custom_fields
from frappe.utils.data import cint
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields


def get_payment_gateway_controller(payment_gateway):
@@ -58,81 +58,83 @@ def make_custom_fields():
if not frappe.get_meta("Web Form").has_field("payments_tab"):
click.secho("* Installing Payment Custom Fields in Web Form")

create_custom_fields({
'Web Form': [
{
"fieldname": "payments_tab",
"fieldtype": "Tab Break",
"label": "Payments",
"insert_after": "custom_css"
},
{
"default": "0",
"fieldname": "accept_payment",
"fieldtype": "Check",
"label": "Accept Payment",
"insert_after": "payments"
},
{
"depends_on": "accept_payment",
"fieldname": "payment_gateway",
"fieldtype": "Link",
"label": "Payment Gateway",
"options": "Payment Gateway",
"insert_after": "accept_payment"
},
{
"default": "Buy Now",
"depends_on": "accept_payment",
"fieldname": "payment_button_label",
"fieldtype": "Data",
"label": "Button Label",
"insert_after": "payment_gateway"
},
{
"depends_on": "accept_payment",
"fieldname": "payment_button_help",
"fieldtype": "Text",
"label": "Button Help",
"insert_after": "payment_button_label"
},
{
"fieldname": "payments_cb",
"fieldtype": "Column Break",
"insert_after": "payment_button_help"
},
{
"default": "0",
"depends_on": "accept_payment",
"fieldname": "amount_based_on_field",
"fieldtype": "Check",
"label": "Amount Based On Field",
"insert_after": "payments_cb"
},
{
"depends_on": "eval:doc.accept_payment && doc.amount_based_on_field",
"fieldname": "amount_field",
"fieldtype": "Select",
"label": "Amount Field",
"insert_after": "amount_based_on_field"
},
{
"depends_on": "eval:doc.accept_payment && !doc.amount_based_on_field",
"fieldname": "amount",
"fieldtype": "Currency",
"label": "Amount",
"insert_after": "amount_field"
},
{
"depends_on": "accept_payment",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
"options": "Currency",
"insert_after": "amount"
}
]
})
create_custom_fields(
{
"Web Form": [
{
"fieldname": "payments_tab",
"fieldtype": "Tab Break",
"label": "Payments",
"insert_after": "custom_css",
},
{
"default": "0",
"fieldname": "accept_payment",
"fieldtype": "Check",
"label": "Accept Payment",
"insert_after": "payments",
},
{
"depends_on": "accept_payment",
"fieldname": "payment_gateway",
"fieldtype": "Link",
"label": "Payment Gateway",
"options": "Payment Gateway",
"insert_after": "accept_payment",
},
{
"default": "Buy Now",
"depends_on": "accept_payment",
"fieldname": "payment_button_label",
"fieldtype": "Data",
"label": "Button Label",
"insert_after": "payment_gateway",
},
{
"depends_on": "accept_payment",
"fieldname": "payment_button_help",
"fieldtype": "Text",
"label": "Button Help",
"insert_after": "payment_button_label",
},
{
"fieldname": "payments_cb",
"fieldtype": "Column Break",
"insert_after": "payment_button_help",
},
{
"default": "0",
"depends_on": "accept_payment",
"fieldname": "amount_based_on_field",
"fieldtype": "Check",
"label": "Amount Based On Field",
"insert_after": "payments_cb",
},
{
"depends_on": "eval:doc.accept_payment && doc.amount_based_on_field",
"fieldname": "amount_field",
"fieldtype": "Select",
"label": "Amount Field",
"insert_after": "amount_based_on_field",
},
{
"depends_on": "eval:doc.accept_payment && !doc.amount_based_on_field",
"fieldname": "amount",
"fieldtype": "Currency",
"label": "Amount",
"insert_after": "amount_field",
},
{
"depends_on": "accept_payment",
"fieldname": "currency",
"fieldtype": "Link",
"label": "Currency",
"options": "Currency",
"insert_after": "amount",
},
]
}
)

frappe.clear_cache(doctype="Web Form")

@@ -151,19 +153,18 @@ def delete_custom_fields():
"amount_field",
"amount_based_on_field",
"amount",
"currency"
"currency",
)

for fieldname in fieldnames:
frappe.db.delete(
"Custom Field",
{"name": "Web Form-" + fieldname}
)
frappe.db.delete("Custom Field", {"name": "Web Form-" + fieldname})

frappe.clear_cache(doctype="Web Form")


def before_install():
# only install for v14
if cint(frappe.get_module("frappe").__version__[:2]) < 14 or not frappe.get_meta("Module Def").has_field("custom"):
if cint(frappe.get_module("frappe").__version__[:2]) < 14 or not frappe.get_meta(
"Module Def"
).has_field("custom"):
return False

불러오는 중...
취소
저장