wordpress 插件一年半赚$1500,还要坚持下去吗?
如何通过 AWS certified solution architect associate (SAA)
一个人如何开发产品
2021年度回顾
中国用户如何免费激活Stripe?
中国用户如何免费激活Stripe?
本文会介绍无需开设海外银行账号或者香港账号,并免费的通过注册激活Stripe账号并提现,亲测有效!
主要通过使用万里汇海外账号绑定激活,其中万里汇是蚂蚁金服旗下的产品,值得可靠。(不是给万里汇打广告哦)
什么是Stripe
想象你是一个跨境电商,想要把产品卖到全球,却面临一个问题,商品标价$100,日本客户想直接支付日元,欧洲客户想支付欧元。。。你不可能要求客户说我只支持美元,请兑换后再支付吧?
所以如果你还不知道Stripe,那推荐你去了解下。作为和PayPal一样存在的支付巨头(现在市值 $950亿),在国外早已火得一塌糊涂,使用他作为支付平台的商家和网站数不甚数,消费者渗透率覆盖了全球135个国家。。。
中国商户,NO
遗憾的是,如果你是身在中国,那么是不能激活Stripe 账号的(不激活只是注册账号倒是可以,但是没法收款和体现,只能测试),可以查看现在商户支持的40多个国家/地区列表, 其中香港是可以的。所以你能看到,这个注册公司地址里是没办法选择中国🇨🇳的,That’s the problem!
如果解决?万里汇 或者 TransferWise
问题的瓶颈在于stripe 激活的时候,需要提供你的商业信息以及银行信息,并且保证银行上的名字和账号里的个人姓名一致。但又由于商业信息的国家地区只有上面提到的,所以也就导致中国用户没办法激活。
解决办法的思路就是,使用万里汇注册个香港账号或者其他国家的银行账号(虽说是虚拟的,但和实际没区别),然后再根据账号的信息拿去Stripe激活,看似简单,但还有很多坑需要趟,且听我慢慢道来。
注册万里汇
点击注册地址 https://portal.worldfirst.com.cn/register,
- 然后按步骤选择支付网关, 这里可以按个人情况多选几个(最好把stripe 勾选上),虽然我也不知道有多大影响
选择类型,可以是个人, 也可以是公司,这里我选的个人
填写基本信息,按部就班的填好就行,注册就算成功
认证账号
注册好了,是非认证状态的,这时是不能创建海外账号,还需要提供相应的信息上传去验证(据说可以支付宝快捷验证,但是我没发现有,只能拍照上传)
认证一般会持续一两天验证,等着收邮件就好了,如果有问题,可以联系自己的万里汇客户经理(真是一对一服务啊,这点好)
创建海外货币账户
终于到了关键步骤了,这里可以创建多个账户,每个账户就像自己银行卡一样,有卡号,为了stripe 注册方便,我创建了一个香港账户和一个美国账户
到了这一步,恭喜你,你已经开通了海外账户!关键是这个银行信息对后面的Stripe激活是非常重要。
创建和激活 Stripe 账号
首先创建Stripe 账号,https://dashboard.stripe.com/register, 国家/地区可以选择香港,创建好之后,登录进入主页面, 这个时候如果你暂时不想激活,是完全可以的,可以切换测试模式进行你的支付开发测试,测试模式基本和在线模式一模一样,除了测试的支付账号是假的以外 (PS, 我就是没激活使用了一年多,纯粹作为开发使用)
激活Stripe 账户
点击 激活你的账户 , 这里看起来有很多步骤,不用怕填错,后面都是可以跳回去改的。
公司结构:
选择香港,或者其他上面货币账号国家,地址可以填银行账号地址,类型可以选个人(如果公司的话,据说stripe 会对你账号保护性或者服务更好),点击下一步
公司代表:必须是你自己在上述银行账号的姓名,否则可能会无法体现到你银行
地址信息可以继续用银行地址,电话号码最好是用中国的,可以选CN, 填写自己号码,因为后面可能会用来用来登录短信验证之类的,身份证ID 这个我没记错的话,是随便找的一个ID(只要位数和格式对了就行) ☹️
银行详情:选择在万里汇创建的银行信息就行
然后一直填下去,保存
激活成功了吗?
上述没问题的话,确实激活成功了,你也可以切换到线上模式去收款了,但是却无法提现(转账)到你银行卡里,还有两个重要的未完成步骤警告:
身份信息不匹配(个人信息验证失败,当然了,ID 都是假的) 和 US Tax Form (美国税收表)
两个问题一个一个解决:
- ID 不匹配,进入提示的配置,只需要上传自己的身份证正反面就好了,一天左右就验证成功(不知道如何验证的,可能是后台人工验证,保证姓名一致就行,所以一定上传自己真实的身份证就,地址用自己中国地址)
- W-8 form,一定要选非美国居民(勾选No),然后点击提交,会被导航至表单填写页面,基本信息stripe 已经帮你预填了,只需要签上个人姓名就好了
documents-for-identity-and-home-address-verification
等着这两个错误完成后,这个账号就算真正激活完成,并可以完成提现(每天,并且非常快)。
万里汇提现到人民币(成功)
现在万里汇香港账号已经有收到的港币了,但如果需要的话,需要转为人民币(可转到支付宝),但根据万里汇客户经理说明,这是需要提供相应凭据,也就是stripe 或者 paypal 上的支付记录,表明来历明确。提现过一次,因为金额不大,并且提供了paypay 的收款记录,所以成功提现。
特别提醒的是,这篇文章目的只是为激活stripe指南, 不为跨境转账成功负责,请酌情选择。
特此声明,本文禁止转载至除 troyyang.com, itstripe.com 以外的网站
Wordpress 插件 Stripe Express 发布啦!
Stripe Express 是什么?
简单来说,Stripe Express 是一款针对wordpress 平台,帮助你使用 stripe 快速,方便完成跨境支付的一款免费插件(扩展功能收费)。其中,包括多种已经创建好的支付组件,包括一次性支付(one-time),电子钱包(支付宝,微信,Apple Pay, Google Pay,下面重点会提到微信和支付宝),表单支付等等组件,需要提及的是,上面的组件都支持常见的各种信用卡,Master card, Visa, 等等等等,以及其他国家地区的主流支付方式比如 Bancontact, FPX, EPS, SEPA, Giropay, Sofort, iDeal。
所以,只有你有一个 Stripe 的账号,那么超过三十多个国家地区的客户都可以向你支付(对于微信和支付宝,你无需申请支付宝或者微信的商家账号,即可免费收款)。
问题: 什么人更需要这个组件?
回答: 现阶段,因为还没集成woocommence, 所以如果你没有一个完整的电子商务网站比如使用 woocommence搭建,只是一个简单的Wordpress 网站,但是你又有自己的产品或者服务需要销售,而你只是想你用户简单的点击购买,付款。
itstripe.com
在我们国内,大部分人肯定知道Paypal,却不知道Stripe,更别说用过,当然也和Stripe 暂不支持中国商家的原因分不开。殊不知,国外Stripe普及程度远大于我们的想象,很多网站都会加上对Stripe 的支持,因为这意味着你的网站可以面向全世界超过30个主要国家的客户收费,包括中国!所以想要做跨境支付的话,Stripe 你必须要熟悉!
众所周知,Wordpress全世界超过40%的网站都是他创建的,而且现在也依旧火爆。再加上之前很多朋友都在咨询我关于 stripe 在wordpress上的问题,所以主要侧重点会是在 stripe express 这款插件上。其次,网站会包括产品介绍,以及插件的文档,还有和stripe 相关集成服务,如果你有集成这方面的需求的话,或者Web 的支付开发,可以联系我们。
Stripe,微信 和 支付宝
这是一个最重要的原因之一促使我想要做这么一个东西。有这么一部分人:1. 小商家或者个人网站用户想要接入微信或者支付宝,方便国内用户收费,2. 国外的中小网站想要针对中国用户微信和支付宝收费。但是对于他们而言,由其老外,要想接入微信或者支付宝支付接口,门槛还是有点高,需要去申请商家账号
stripe 却在这方面有着天然优势,由于已经和alipay 和 wechat 达成协议,Stripe 完全可以实现上面的收费,其中stripe 会收取3.4% + $0.50每笔的服务费。
之前写过一篇关于 stripe集成 微信和支付宝的文章,反响挺大的,看到很多评论和转载,也收到很多咨询的邮件,但是之前的那篇从技术角度其实有点老了,我会另外抽时间重新写一个更通用的集成方式(已经在这款插件中实践了)
后续
回想这半年多的开发时间(包括插件和官网),白天正常上班,晚上继续开发,连周末都不想出门,像打鸡血一样的完善产品,终于迎来了发布的日子。无论这款插件将来如何,安装量怎样,有过这么一段为了某个目标而全力以赴的日子也是极好的!
Mobx在项目中的实践 及 与Redux的比较
之前在公司FEE内部做过一次技术分享,主要关于Mobx在项目中的使用一年后的体验以及和Redux 的一些比较(因为我们项目之前的状态管理选型选择的是mobx,而其他项目组的同学选择主要是Redux或者还在纠结如何选)。
以下都是根据查询各种资料后的个人理解概览
Mobx Overview
Mobx looks like a properties tracking and reaction lib.
基础部分就省了,只说结论:Mobx 看起来是属性追踪及作出相应反应的库,和Redux 不一样的是,他的状态是mutable的。
Mobx 4 & 5
- Mobx 4 Limitations (Observable)
- Mobx 5 Proxy based (Only ES 6 Browser, no polyfill)
Mobx & Third-Party view lib
- mobx & mobx-react
- redux & react-redux
- mobx & mobx-arch & mobx-backbone 有吗???
Mobx 是可以单独使用的,这点和Redux一样,可以不需要依赖于任何UI 库像,React, Vue,当然如果把他们结合到一起,那才能发挥出最大的作用,所以就理所应当的有mobx-react。
我们公司内部有个UI 库叫arch,很老的了,requirejs时代的,比react, vue, angular还早,没有响应式的更新,核心只有一个render 方法,所以其实可以通过Mobx 简单改造为响应式的,一旦外部属性发生变化,就会触发重新渲染,至于内部状态嘛,呵呵,不考虑了,反正这只是个例子。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27var { observable, autorun } = require("mobx");
var Entity = require('xx/xxxx/entity');
var todoStore = observable({
todos: [],
get completedCount() {
return this.todos.filter(todo => todo.completed).length
}
})
autorun(function () {
// For Backbone
this.xxxBackBoneComponent = new Entity({
model: todoStore.todos,
editable: true
});
// For Arch
active.render($html, () => {
this.xxArchComponent = arch.getComponent(xxx);
});
})
todoStore.todos[0] = {
title: "Take a walk",
completed: false
}
Mobx Store Design
- Offical guide on Store design
- Best Practice
- UI State & Domain State
这是我觉得最难的部分,如何设计好Mobx的Store?官方给出的一个guide 是划分为Domain store 和 UI store。Domain store和Redux的one-single store 可不一样,这里是可以有多个的,像users, books, movies, orders 都可以是一个Domain Store, 至于UI store,暂时我们只是存储一些全局的属性。所以,我们的项目中Store的结构大致如下:1
2
3
4
5
6
7stores
--root.ts
--domain
----aaaStore.ts
----bbbStore.ts
--ui
----application.ts
root.ts初始化所有domain和ui store:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21export default class RootStore {
@observable
aaStore;
@observable
bbStore;
@observable
applicationUIStore;
constructor() {
// Domain Store Init
this.aaStore = new AStore(this);
this.bbStore = new BStore(this);
...
// UI Store Init
this.applicationUIStore = new ApplicationUIStore(this);
...
}
}
但是在实际的问题中,我们发现大部分的状态其实都是本地UI状态,(也许有人说用setState啊,如果业务复杂,状态很多, 并且基本会依赖其他store,最好抽出来)所以,问题来了,这些ui store我们放在哪里呢?同时,我们需要把Container 组件里的状态隔离开来,为什么隔离,一是因为UT 不好写(因为有inject,所以在UT里需要写很多Provider),二是傻瓜组件更不容易出错,参考Redux的connect用法,我们得到下面的结构:1
2
3ContainerAComponent
--ContainerAComponent.tsx
--ContainerAComponentUIStore.ts
ContainerAComponentUIStore.ts1
2
3
4
5
6
7
8
9
10
11
12
13export default class ContainerAComponentUIStore {
rootStore;
constructor(rootStore) {
this.rootStore = rootStore;
}
@observable
addHoc = '';
@action.bound
onAdhocChange = (addHocNewValue) => {
....
}
ContainerAComponent.tsx1
2
3
4
5
6
7export class ContainerAComponent extends React.Component {
handleAdhocChange = (e) => {
this.props.onAdhocChange(e.target.value);
}
...
}
export default connectComponentStore(ContainerAComponent, ContainerAComponentUIStore);
这样,我们导出了两个组件,一个是ContainerAComponent,就是一个简单组件,我们可以通过传统传props的方式去测试组件核心内容,另一个是HOC组件,其实是不用测试的。
而至于connectComponentStore方法,就是一个很简单的HOC1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29export default (WrapperedComponent, ComponentStore) => {
@inject('appStore')
@observer
class Connect extends React.Component {
@observable componentStore;
constructor(props) {
super(props);
this.componentStore = new ComponentStore(props.appStore);
this.ref = createRef();
}
static displayName = `${WrapperedComponent.displayName || WrapperedComponent.name}-withUIStore`
componentDidMount() {
this.componentStore.mapState(this.props);
}
componentDidUpdate(preProps, preState) {
this.componentStore.mapState(this.props);
}
render() {
return (<WrapperedComponent ref={this.ref} {...this.componentStore.toProps} {...this.props} />);
}
}
return Connect;
};
我们业务里,绝大部分都是用到的这种本地UI Store + 简单组件组合这种方式,也许就是所谓的local state component (忘了哪里听到的了)
Mobx-State-Tree(MST)
也许MST在大型项目中使用是个很好的方式,但我们暂时还没有去尝试。
Project Structure
下面是Mobx的一些项目组织结构参考资料:
https://medium.com/@daniel.bischoff/how-to-structure-your-mobx-react-app-8fd6d9d821a4
https://github.com/gothinkster/react-mobx-realworld-example-app
Mobx-React vs Redux-React
个人简单的一些看法:
- Workflow
- Freestyle vs Strict
- OOP styles vs FP
- Small vs Large
- Time-traval problem (Resolved by MST)
- Container components (Inject vs Connect)
- redux-crud-example & mobx-crud-example
https://medium.com/@cameronfletcher92/mobdux-combining-the-good-parts-of-mobx-and-redux-61bac90ee448
https://www.sitepoint.com/redux-vs-mobx-which-is-best/
Learning Redux
在一些小项目中用过Redux, 不得不说,Redux的学习成本要比Mobx高得多,比如下面的点,
redux, reducer, action, container component, selectors(reselect), redux-thunk, normalizing, ducks, and more waiting…
Others links
Mobx-Best-Practice
Decorator (ES7/TS) vs no-decorators
End
如果你有更好Mobx使用的一些心得,欢迎交流!
纯JS实现按多列排序
重要的事情还是要说的
项目里没引用 lodash (因为和 underscore.js 冲突)
问题
数据结构类似这种:1
2
3
4
5
6const testData = [
{ name: '1', primary: true, startDate: '2018-01-01T08:00:00Z', endDate: '2018-05-01T08:00:00Z' },
{ name: 'A', primary: true, startDate: '2018-02-01T08:00:00Z', endDate: '2018-06-01T08:00:00Z' },
{ name: 'a', primary: true, startDate: '2019-02-01T08:00:00Z', endDate: '2019-05-01T08:00:00Z' },
{ name: 'b', primary: false, startDate: '2019-02-01T08:00:00Z', endDate: '2019-02-01T08:00:00Z' },
]
最近项目中有大量的对排序的新需求,由其是按多列来排序, 新需求大致如下:
- Archived 为true的排列到最后,否则排最前面
- 然后,按照 StartDate 时间,如果最新,则排前面
- 然后,如果 StartDate 相同,则按照 EndDate 来排,
- 然后,如果 EndDate 也相同,则按照 name 的字母表的顺序排
同时呢,之前项目中也有很多类似的需求:
- 先按照 ModifiedDate 排,
- 如果相同,则按 name 字母表顺序
或者
- Primary 为true 的排前面
- 如果Primary 相同, 按照 name 字母表排序
还有更多的类似需求,我们项目里原来有个 Sort.js 的公共方法来处理这些排序,选取了其中最长的一个 (其实上面需求的每一个实现都和这个差不多)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29const sortFlattenPrograms = (flattenPrograms) =>
flattenPrograms.sort((a, b) => {
// first sort by archived: unarchived first
if(a.archived && !b.archived) {
return 1;
} else if(!a.archived && b.archived) {
return -1;
}
// sort by start date: latest first
let dateCompareResult = compareDateLatestFirst(a.startDate, b.startDate);
if(dateCompareResult !== 0) {
return dateCompareResult;
}
// sort by end date: latest first
dateCompareResult = compareDateLatestFirst(a.endDate, b.endDate);
if(dateCompareResult !== 0) {
return dateCompareResult;
}
// sort by program name - location name: alphabetically (ignore case)
const nameCompareResult = compareStringAlphabeticallyIgnoreCase(getProgramFullName(a), getProgramFullName(b));
if(nameCompareResult !== 0) {
return nameCompareResult;
}
return 0;
});
是不是很长,很丑,而且这只是一个排序,还有很多这种和0比较,然后再比较,所以继续加下去肯定不可取,维护是个很大的问题,UT 也很难写,要是能抽出中间部分就好了???
解决办法
先贴代码,其实核心就是抽取上面的各种comparator, 并且采用链式的方式执行,这里使用reduce方法来取了个巧,其实,查看了lodash的实现后, 他们采用的是 while 实现。
注意排序的顺序,是按照从右到左,我想的是尽量和 functional programming 的方式来写,并且compose 方法在lodash 里也是这个顺序,如果想改为从左往右,只需要将 reduce 改为 reduceRight 即可1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18/**
* Sort by order list from right to left
* For example: we want to order by start date, if date equal, then order by end date, if equal, then name
* composeOrderBy([oderByName, orderByEndDate, orderByStartDate])
* @param {*} comparators
*/
const composeOrderBy = (comparators) => {
const makeChainedComparator = (first, next) => {
return function (a, b) {
var result = first(a, b);
if(result !== 0) return result;
return next(a, b);
};
};
return comparators.reduce(function (chained, first) {
return makeChainedComparator(first, chained);
});
};
所以,上面的需求可以简单改为下面,其实comparators 是一个我预先定义好的各种比较方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 预先定义的方法
comparators = {
compareStringField: (field, ignoreCase = true)=> (a, b) => { ... },
compareBoolField: (field, trueFirst = true) => (a, b) => { ... },
compareDateLatestFirst: (field) => (a, b) => { ... },
}
data.sort(composeOrderBy([
comparators.compareNameIgnoreCase(),
comparators.compareDateLatestFirst('endDate'),
comparators.compareDateLatestFirst('startDate'),
comparators.compareBoolField('archived', false)
]));
data.sort(composeOrderBy([
comparators.compareNameIgnoreCase(),
comparators.compareDateLatestFirst('modifiedDate')
]));
最终还是需要用到 array的sort 方法,但由于这不是纯函数,所以保险的做法就是调用sort前,先在clone一下
神奇的 ES6 继承执行顺序问题
刷推的时候无意间发现一位google 工程师发的一个感叹,感叹发现的一个神奇的JS 6继承顺序问题。。。
仔细看了看,确实好神奇,于是好奇的看了看babel转换出的结果:
1 | var SuperClass = function SuperClass() { |
就和他猜测的一样:没有supper的时候,字段的初始化是早于构造函数执行的,有supper的时候,字段初始化是在构造函数里的super后执行!
个人看法是故意放super之后是为了能在字段里访问到父类的字段?